Где в реестре находятся настройки delphi. Назначение разделов реестра

30.10.2019 Социальные сети

Использование хранимых функций СУБД для реализации бизнес-логики или её части, всегда было камнем преткновения. С одной стороны баррикад DBA и программисты БД, с другой - разработчики backend.
Рискну навлечь на себя гнев из обоих лагерей, но всё же просуммирую плюсы и минусы и изложу свои соображения о том, когда стоит писать код в хранимых функциях, а когда следует выносить наружу.

Начнём с аргументов против:

Размазывание бизнес-логики

Это, на самом деле не проблема СУБД и ХФ, как инструмента - это проблема их неверного использования. У программиста бд может возникнуть желание описать всю логику реализуемого действия в хранимой функции - действительно, ведь все данные вот они, под рукой. Если программист поддастся на искушение, а его руководитель не возразит, в будущем могут возникнуть проблемы с узостью интерфейса со внешней системой (например, с сервером приложений) - придётся добавлять новые параметры, усложнять логику и т.п. Это даже может привести к тому, что появятся «дублирующие» ХФ со слегка иным функционалом.

Скудность языка СУБД

Есть такое дело. Традиционные языки для написания ХФ pl/sql, t-sql, pl/pgsql довольно примитивны по сравнению с современными языками общего назначения. Стоит заметить, что есть возможность писать ХФ и на более продвинутых языках, например Java в Oracle или Python в postgresql.

Непереносимость хранимых функций

Имеется в виду несовместимость диалектов процедурных языков разных СУБД. Многоплатформенность как раз на уровне - благодаря поддержке разных ОС и архитектур в самих СУБД и независимости встроенных языков от внешней платформы. Здесь опять решение зависит от специфики проекта. Если проект тиражируемый, причём вы не контролируете платформу (классический пример - CMS), то переносимость вам необходима и использование ХФ - только добавит головной боли. Если же проект уникальный, либо внедрения будут происходить унифицировано (например в разных филиалах одной компании), то про непереносимость между разными СУБД можно забыть.

Отсутствие необходимых навыков у команды и высокая «стоимость» соответствующих специалистов

Это, на мой взгляд, самый серьёзный аргумент против использования ХФ. Тут всё зависит от масштабов проекта. Грубо говоря, использование хранимого кода на стороне СУБД оправдано в средних-крупных enterprise проектах. Если проект помельче - овчинка выделки не стоит. Если проект огромный сверхнагруженный, то архитектура с ХФ и РСУБД упрётся в проблемы масштабирования - тут необходимо использование специфического хранилища и подхода к обработке данных.

Теперь плюсы:

Скорость

При обработке даже небольших объёмов данных во внешнем приложении мы тратим дополнительное время на передачу по сети и преобразование данных в нужный нам формат. К тому же в СУБД уже встроены, отлажены и протестированы близкие к оптимальным алгоритмы обработки данных, вашим программистам незачем практиковаться в изобретении велосипедов.

Сокрытие структуры данных

С ростом и эволюцией программной системы схема данных может и должна меняться. Хорошо спроектированный программный интерфейс на ХФ позволит менять схему данных не изменяя код внешних приложений (которых может быть несколько). Отсюда органично вытекает и разделение ролей разработчиков, которые работают с БД и знают её структуру, и разработчиков внешних приложений, которые должны знать лишь предоставляемый API. При использовании динамического SQL на стороне приложения, для подобного разделения вводятся дополнительные слои программных абстракций БД, различные ORM.

Гибкое управление правами доступа

Хорошей практикой является ограничение пользователя, под которым «ходит» в базу клиентское приложение в правах таким образом, что он не имеет прав на чтение и изменение никаких объектов. Лишь выполняет разрешённые ему функции. Таким образом можно жёстко контролировать какие действия доступны клиенту, уменьшается вероятность нарушения целостности данных из-за ошибки клиентского приложения.

Меньшая вероятность SQL injection

При использовании динамического SQL со стороны клиентской программы, клиентская программа передаёт СУБД SQL команды в виде строк, предварительно формируемых в коде. При формировании этих строк программисту нужно быть предельно внимательным, чтобы не допустить возможности непредусмотренной модификации SQL команды. При использовании ХФ SQL код на стороне приложения обычно статический, и выглядит, как простой вызов ХФ, параметры которой передаются не строками, а через placeholders (:variable) через механизм binding. Конечно это не исключает возможность SQL injection полностью (ведь можно умудриться в ХФ конкатенировать строку, переданную параметром с текстом динамически выполняемого SQL запроса), но значительно уменьшает её вероятность.

Повторное использование SQL

Реализуя логику работы с данными в хранимом слое мы получаем привычную нам иерархическую модель повторного использования SQL кода.
При использовании динамического SQL повторное использование запросов затруднено.
Например пусть есть система A на базе ХФ и система Б на базе динамического SQL. В обеих системах есть функция получения цены товара get_price. В случае A - это хранимая функция или отображение (view), в случае Б, допустим, процедура на java, через JDBC выполняющая SQL запрос. Есть задача - получить общую стоимость товара на складе. В случае A мы джоиним get_price прямо в запрос, получающий список товаров на складе (в случае, если get_price - view или ХФ на SQL, как например в PostgreSQL, то оптимизатор разворачивает запрос inline - тем самым получается один запрос, который быстро находит сумму).
В случае B есть два варианта - либо пробежать по курсору с выборкой товаров на складе и n раз вызвать get_price (а это значит что вся выборка должна передаться по сети на клиент) либо забыть про повторное использование и написать подзапрос, дублирующий тот, что был уже написан в get_price. Оба варианта - плохие.

Простая отладка SQL

Упрощается отладка (по сравнению с разнородной процедурой внешний код+sql)
В системах с динамическим SQL (любые ORM) даже простая задача поиска проблемного куска SQL может оказаться сложной.
Семантическая и синтаксическая проверка SQL на этапе компиляции.
Возможность профилирования функций и поиска узких мест.
Возможность трассировки уже запущеной и работающей системы.
Автоматический контроль зависимостей - при изменении определения объекта инвалидируются зависимые сущности.

Когда писать бизнес-логику в БД?

Если важна скорость обработки данных
Обработка данных прямо на месте их хранения зачастую даёт значительный прирост скорости обработки. Становятся возможными такие оптимизации, как, например, агрегации на уровне хранилища данных - данные с массива даже не передаются на сервер СУБД, не говоря о клиенте.
Когда важна целостность и непротиворечивость данных
В хранимых функциях с явным управлением транзакциями и блокировками проще обеспечить целостность данных и атомарность операций. Конечно всё это может быть реализовано и снаружи, но это отдельная и большая работа.
Данные имеют сложную, но устоявшуюся структуру
Плоские и слабо взаимосвязанные структуры часто не требуют всего богатства инструментов обработки, которые предлагают СУБД. Для них можно использовать сверхбыстрые key-value хранилища и кеширование в памяти.
Сложно организованные сильно связанные иерархические и сетевые структуры - явный показатель, что ваши знания РСУБД пригодятся!

Когда выносить код наружу?

Работа с внешними данными
Если специфика системы такова, что данных, приходящих на обработку снаружи (с датчиков, из других систем) больше, чем данных, сохраняемых в БД, то многие плюсы БД, как платформы программирования теряются. Оказывается проще обработать поступающие даннные снаружи и сохранить результат в БД, чем сначала всё пихать в БД, а потом обрабатывать. Здесь соблюдается тот же принцип - обрабатывать данные как можно ближе к источнику, о котором мы говорили выше применительно обработке данных, уже хранящихся в БД.
Сложные алгоритмы
Сложные или высоко-оптимизированные алгоритмы-числодробилки лучше писать на более приспособленных для этого языках. Встроенные языки РСУБД очень мощны (в том смысле, что высокоуровневые, а не гибкие), но за счёт этого имеют высокий overhead.
Highload
В сверхвысоконагруженных системах обычные подходы к сериализации транзакций и синхронизации серверов кластера становятся узким местом. Для таких систем характерны уникальные решения под конкретные задачи, универсальные и мощные системы РСУБД часто оказываются слишком медлительными при нагрузках в сотни тысяч конкурентных транзакций в секунду.

Вывод такой, что чёткого алгоритма нет. Каждый раз решение остаётся за архитекторами и менеджером и от него зависит то, завязнет ли проект в проблемах с race conditions и неконсистентностью данных NoSQL, проблемах с производительностью и отладкой запросов ORM, или упрётся в проблемы масштабирования СУБД при использовании хранимых функций. Поэтому - принимайте верные решения:)

22 ответов

В моем опыте написания в основном приложений WinForms Client/Server это простые выводы, к которым я пришел:

Использовать хранимые процедуры:

  • Для любой сложной работы с данными. Если вы собираетесь делать что-то действительно требующее таблиц курсора или temp, это, как правило, самый быстрый способ сделать это в SQL Server.
  • Если вам нужно заблокировать доступ к данным. Если вы не предоставляете доступ к таблице пользователям (или роли или чему-либо еще), вы можете быть уверены, что единственный способ взаимодействия с данными - через создаваемый вами СП.

Использовать специальные запросы:

  • Для CRUD, когда вам не нужно ограничивать доступ к данным (или делаете это по-другому).
  • Для простых поисков. Создание SP для множества критериев поиска - это боль и сложность в обслуживании. Если вы можете создать достаточно быстрый поисковый запрос, используйте это.

В большинстве моих приложений я использовал как SP, так и ad-hoc sql, хотя я считаю, что я использую SP все меньше и меньше, поскольку они в конечном итоге являются кодом, как С#, только сложнее контролировать, тестировать и поддерживать. Я бы рекомендовал использовать ad-hoc sql, если вы не можете найти конкретную причину.

Хранимые процедуры представляют собой контракт на программное обеспечение, который инкапсулирует действия, предпринятые против базы данных. Код в процедурах и даже сама схема базы данных может быть изменен без влияния на скомпилированный, развернутый код, так что входы и выходы процедуры остаются неизменными.

Встраивая запросы в ваше приложение, вы тесно связываете себя с вашей моделью данных.

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

Я думаю, что это основной конфликт между людьми, которые должны поддерживать базу данных и людей, которые разрабатывают пользовательские интерфейсы.

Как человек с данными, я бы не стал рассматривать работу с базой данных, к которой обращаются через adhoc-запросы, потому что их трудно эффективно настраивать или управлять. Как я могу узнать, что повлияет на изменение схемы? Кроме того, я не думаю, что пользователям следует предоставлять прямой доступ к таблицам базы данных по соображениям безопасности (и я имею в виду не только атаки SQL-инъекций, но также и потому, что это базовый внутренний элемент управления, который не допускает прямых прав и требует от всех пользователей используйте только procs, предназначенные для приложения, чтобы предотвратить возможное мошенничество. Любая финансовая система, которая позволяет напрямую вставлять, обновлять или удалять права на таблицы, имеет огромный риск для мошенничества. Это плохо.).

Базы данных не являются объектно-ориентированными, а код, который кажется хорошим из объектно-ориентированной точки зрения, может быть крайне плохим с точки зрения базы данных.

Наши разработчики сообщают нам, что они рады, что весь наш доступ к базам данных осуществляется через procs, потому что он значительно ускоряет исправление ошибки, зависящей от данных, а затем просто запускает proc в рабочей среде, а не создает новую ветвь кода и перекомпилировать и перезагрузить в производство. Мы требуем, чтобы все наши процессы были в подрывной деятельности, поэтому контроль источника не является проблемой вообще. Если он не находится в Subversion, он будет периодически удаляться dbas, поэтому нет никакого сопротивления использованию Source Control.

Хранимые процедуры, безусловно, подходят... они скомпилированы, имеют план выполнения перед началом работы, и вы можете заниматься управлением правами на них.

Я не понимаю эту проблему с исходным кодом на хранимой процедуре. Вы определенно можете их контролировать, если только вы немного дисциплинированы.

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

Я хотел бы процитировать Tom Kyte от Oracle здесь... Вот его правило о том, где писать код... хотя и немного несвязанный, но хорошо знаю, я думаю.

В нашем приложении есть слой кода, который предоставляет содержимое запроса (а иногда и вызов хранимой процедуры). Это позволяет нам:

  • легко получить все запросы при управлении версиями
  • чтобы сделать все изменения для каждого запроса для разных серверов баз данных
  • исключает повторение одного и того же кода запроса через наш код

Контроль доступа реализуется в среднем слое, а не в базе данных, поэтому нам не нужны хранимые процедуры. Это в некотором роде средняя дорога между специальными запросами и хранимыми процедурами.

Существуют убедительные аргументы для обеих хранимых процедур, которые находятся в центральном репозитории, но (потенциально) трудно переносится, а специальные запросы легче отлаживать, поскольку они с вашим кодом, но они также могут быть сложнее найти в коде.

Аргумент, что хранимые процедуры более эффективны, больше не содержит воды. текст ссылки

Выполнение google для хранимой процедуры vs Dynamic Query покажет достойные аргументы в любом случае и, вероятно, лучше для вас принять ваше собственное решение...

Некоторые вещи, о которых нужно подумать: Кому нужны хранимые процедуры, Anyways?

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

Procs по причинам, упомянутым другими, а также проще настроить proc с помощью профилировщика или частей proc. Таким образом, вам не нужно рассказывать кому-либо о запуске своего приложения, чтобы узнать, что отправляется на сервер SQL

Если вы используете ad-hoc-запросы, убедитесь, что они параметризированы

Параметрированный SQL или SPROC... не имеет значения с точки зрения производительности... вы можете запросить оптимизацию одного из них.

Для меня последнее оставшееся преимущество SPROC заключается в том, что я могу исключить много прав на управление правами SQL, только предоставляя свои права на вход для выполнения sprocs... если вы используете Parametized SQL, логин, связанный с вашей строкой подключения, имеет намного больше прав (запись любого вида оператора выбора на одну из таблиц, к которым у них есть доступ, например).

Я по-прежнему предпочитаю параметризованный SQL, хотя...

Аргумент производительности sproc является спорным - 3 верхних RDBM используют кэширование плана запросов и некоторое время. Его документально подтвердили... Или еще 1995 год?

Однако встраивание SQL в ваше приложение также является ужасным дизайном - обслуживание кода, по-видимому, является недостающей концепцией для многих.

Если приложение может начинаться с нуля с помощью ORM (приложения с зеленым полем далеки от нескольких!), это отличный выбор, поскольку модель вашего класса управляет вашей моделью БД и экономит время.

Если структура ORM недоступна, мы использовали гибридный подход создания XML файла SQL-ресурсов для поиска строк SQL по мере необходимости (они затем кэшируются инфраструктурой ресурсов). Если SQL нуждается в каких-либо незначительных манипуляциях, выполненных в коде, - если требуется большая манипуляция строкой SQL, мы переосмыслим этот подход.

Этот гибридный подход облегчает управление разработчиками (возможно, мы являемся меньшинством, поскольку моя команда достаточно ярка, чтобы читать план запроса), а развертывание - это простая проверка из SVN. Кроме того, он упрощает коммутацию RDBM - просто замените файл ресурсов SQL (не так просто, как инструмент ORM, конечно, но это работает с устаревшими системами или не поддерживаемой базой данных)

Мой опыт состоит в том, что 90% запросов и/или хранимых процедур вообще не должны записываться (по крайней мере, вручную).

Доступ к данным должен генерироваться как-то автоматически. Вы можете решить, хотите ли вы статически генерировать процедуры во время компиляции или динамически во время выполнения, но если вы хотите добавить столбец в таблицу (свойство объекта), вы должны изменить только один файл.

Я предпочитаю хранить все данные доступ в коде программы, в котором уровень доступа к данным выполняет прямые SQL-запросы. С другой стороны, логика управления , которую я поместил в базу данных в виде триггеров, хранимых процедур, пользовательских функций и еще чего-то. Примером того, что я считаю достойным базы данных, является генерация данных - предположим, что у нашего клиента есть имя FirstName и LastName. Теперь для пользовательского интерфейса требуется DisplayName, которое выводится из некоторой нетривиальной логики. Для этого поколения я создаю хранимую процедуру, которая затем запускается триггером всякий раз, когда обновляется строка (или другие исходные данные).

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

Я могу просто отключить идею SP, увидев так много плохо спроектированных. Например, в одном проекте, в котором я участвовал, использовался набор хранимых процедур CRUD для каждой таблицы и каждый возможный запрос, с которым они столкнулись. При этом они просто добавили еще один совершенно бессмысленный слой. Больно даже думать о таких вещах.

Реестр - это системная база данных. Получить доступ к ней можно написав в командной строке ("ПУСК > "Выполнить") слово "RegEdit" - при этом запуститься программа для редактирования реестра. Окно этой программы поделено на две части. В левой (более узкой панели) показана древовидная структура ключей. Ключ - это раздел, отвечающий за какие-либо установки. Сами установки называются параметрами, находящимися в правой панели. Каждый параметр имеет своё имя, значение и тип. Параметры бывают строкового типа, двоичного и типа DWORD. Их очень много, но их назначение зависит от того, в каком ключе находится той или иной параметр. Ключи делятся между шестью основными разделами:

  • HKEY_CLASSES_ROOT - Содержит информацию об OLE, операциях перетаскивания (drag-and-drop - с англ. перетащить-и-отпустить) и ярлыках. В данном разделе можно так же указать программы, запускаемые при активизации файлов определённого типа. Данный раздел является псевдонимом для ветви HKEY_LOCAL_MACHINE\Software\Classes
  • HKEY_CURRENT_USER - Содержит индивидуальные установки для каждого пользователя, зарегистрированного в системе. Данный раздел является псевдонимом для ветви HKEY_USERS
  • HKEY_LOCAL_MACHINE - Содержит аппаратные и программные установки, необходимые для функционирования оборудования и программ. Данный раздел так же хранит конфигурацию Windows.
  • HKEY_USERS - Содержит установки пользователей и соответствующие конфигурационные данные, такие как цвет окна, расположение элементов на рабочем столе, обои, заставки.
  • HKEY_CURRENT_CONFIG - Содержит информацию о текущем аппаратном профиле. Если вы не используете аппаратные профили, данный раздел содержит установки Windows по умолчанию.
  • HKEY_DYN_DATA - В отличие от других разделов, которые хранят статистические данные (неизменяющиеся во время сеанса), данный раздел содержит указатели на динамические данные (постоянно изменяющиеся во время работы компьютера). Windows использует данный раздел для отслеживания профилей оборудования plug-and-play, статистики по производительности и драйверов виртуальных устройств VxD.

Все данные системного реестра заключаются в двух файлах, находящихся в директории Windows - это System.dat и User.dat.

Структура reg-файлов

Знание реестра Windows будет не полным без умения написать reg-файл. Начнем с того, что это такое. Reg-файл - это файл, имеющий определенную структуру и содержащий информацию, которая может быть импортирована в реестр. Если была заблокирована работа с редактором реестра, то наиболее легким способом подредактировать реестр будет создание и импортирование reg-файла (конечно, можно выйти в DOS, в защищенный режим, воспользоваться другими программами, но это все гораздо сложнее, а главное дольше).

К reg-файлам предъявляются определенные требования по структуре. Начнем с того, что в первой строке файла обязательно должно быть введено REGEDIT4. Обратите внимание на то, что буквы должны быть большие. Кроме этого в первой строке ничего быть не должно. После этого текста ОБЯЗАТЕЛЬНО должна быть пустая строка. Затем, указывается раздел реестра, в котором надо прописать или изменить какие-то параметры. Название раздела должно быть заключено в квадратные скобки [...]. Ниже прописываются параметры, которые надо добавить, по одному параметру в строке. Если вам надо провести изменения в нескольких разделах, то вы должны оставлять одну пустую строку между последним параметром предыдущего раздела и названием следующего раздела. Может немного запутанно, но вот как это должно выглядеть:

REGEDIT4 "param1"="znachenie1" "param2"="znachenei2" "param3"="znachenie3" "param_1"="znachenie_1"

Последняя строка в файле должна быть ПУСТОЙ. После того, как вы создали такой файл, просто запустите его как обычную программу, вам будет выдан запрос о необходимости провести изменения в реестре, и после положительного ответа информация из файла будет импортирована. О результатах импортирования Windows сообщит в появившемся после этого окне.

Теперь пару слов о параметрах, которые можно добавлять. Как вы, наверное, обратили внимание, в приведенном выше примере добавляются параметры с помощью строк типа "param1"="znachenie1". Т.е. таким образом добавляется СТРОКОВЫЙ параметр с именем "param1" и значением "znachenie1". Но ведь существуют еще и параметры двоичные и DWORD. Формат записи для их добавления несколько другой. Для параметров типа DWORD используется строка:

"param"=dword:XXXXXXXX

Здесь "param" - имя параметра, dword - указывает на тип этого параметра (буквы должны быть обязательно маленькие!) и после двоеточия следует значение из восьми цифр в шестнадцатеричном (!) формате. Однако большинство параметров DWORD имеют значение либо 0, либо 1, значит, вы должны написать соответственно либо 00000000, либо 00000001 вместо значков ХХХХХХХХ. Пробелы в строке не допускаются.

Для добавления двоичного параметра формат записи несколько иной:

"param"=hex:XX,XX,XX,....

Теперь расшифруем эту строку. С названием параметра все понятно, после знака "=" идет hex, т.е. указывается, что это будет двоичный параметр, затем идут шестнадцатеричные числа, отделенные запятой. Например, если вам надо добавить двоичный параметр равный "be 00 00 00", то вы пишете строку:

"param"=hex:be,00,00,00

В реестре существуют параметры "По умолчанию" ("Default"). Чтобы присвоить им какое-то значение через reg-файл, надо добавить такую строку:

@="znachenie"

Здесь значок "@" показывает, что у нас присваивается значение параметра "По умолчанию". Обратите внимание на то, что он не заключается в кавычки.

Ниже приведен пример простенького reg-файла, который прописывает в реестр сайт, устанавливающий домашнюю страничку в Internet Explorer"e:

REGEDIT4 "Start Page" = http://www.virun.com.ua

На первый взгляд все очень просто. Но есть у reg-файлов одна особенность: с помощью них нельзя удалять параметры в реестре, правда, можно удалить раздел целиком. Для удаления раздела из реестра надо перед его именем в квадратных скобках поставить символ "-". Вот как это выглядит:

[-HKEY_LOCAL_MACHINE\Software\QuickSoft\QuickStart]

Благодаря этой записи, подраздел "QuickStart" из раздела "QuickSoft" будет удален со всем содержимым. Однако, как быть с параметрами? Ведь их удалять нельзя. Установка ограничений на доступ к различным настройкам оболочки Windows производится с помощью параметров типа DWORD. При этом, если значение параметра равно 1 (00000001), то ограничение включено, а если равно 0 (00000000), то ограничение отключено. Таким образом, параметры удалять вовсе не обязательно, достаточно просто присвоить им значения равные нулю.

Использование реестра

Как нам уже известно, реестр представляет собой иерархическую базу данных, cостоящую из секций, подсекций и элементов. Каждая секция имеет свое назначение. Хранить данные о пользовательских программах Microsoft рекомендует в секции HKEY_CURRENT_USER и подсекции Software. В этой подсекции вы создаете подсекцию, идентифицирующую вашу программу или фирму, и уже внутри нее располагаете данные.
Модуль Registry

Для упрощения работы с регистратором в состав Delphi (начиная с версии 2.0) входит модуль REGISTRY, содержащий реализацию трех классов, - TRegistry, TRegistryIniFile и TRegIniFile.
Внимание! Чтобы использовать свойства и методы классов TRegistry, TRegistryIniFile и TRegIniFile, необходимо включить в список uses модуль Registry.

TRegIniFile

Собственно говоря, задача класса TRegIniFile - упростить перенос 16-битных программ в среду Windows 95. Методы этого класса эквивалентны методам класса TIniFile в 16-битной версии Delphi. Класс TRegIniFile позволяет обращаться к секции HKEY_CURRENT_USER, считывать и записывать строки (методы ReadString и WriteString), целочисленные значения (методы ReadInteger и WriteInteger), логические значения (методы ReadBool и WriteBool), секции (методы ReadSection , ReadSections и ReadSectionValues), удалять секции (метод EraseSection) и элементы (метод DeleteKey). Рассмотрим на примерах, как используются функции этого класса.

Microsoft рекомендует записывать данные, относящиеся к вашей программе, в подсекции секции HKEY_CURRENT_USER_Software. Предположим (не особенно фантазируя на эту тему), что ваша программа называется RegDemo, и данные для нее располагаются в секции Software\RegDemo. Ниже мы покажем, как поместить в регистратор строчные, целочисленные и логические данные, а затем считать их, - этих операций будет достаточно для того, чтобы сохранить в регистраторе параметры нашей программы, а затем считать их.

Прежде чем записать данные в определенную секцию, ее необходимо создать. Это происходит при вызове конструктора объекта TRegIniFile. В качестве параметра вы указываете название секции, и если таковой не существует, она создается:

RegFile:= TRegIniFile.Create(SubKey);

После того как файл регистратора открыт (и создана определенная секция), мы можем записать данные. Поддерживаются три типа данных: целочисленные, логические и строчные данные. Для записи этих данных существуют методы WriteInteger , WriteBool и WriteString . В качестве параметров указываются:

  • название подсекции;
  • название элемента;
  • записываемые данные.

Так, чтобы записать значение элемента MyIntVal в подсекции IntKey, следует выполнить код:

RegFile.WriteInteger(IntKey, "Int_Val", 32000);

а для того чтобы прочесть значение, необходимо вызвать метод ReadInteger (в качестве параметров указываются название подсекции, название элемента и значение по умолчанию):

RegFile.ReadInteger(IntKey, "Int_Val", 0));

Для чтения логических и строчных данных используются соответственно методы ReadBool и ReadStr , а для их записи – методы WriteBool и WriteString .

Расссмотрим пример использования перечисленных выше методов класса TRegIniFile. Расположим в форме компонент Memo, две группы GroupBox и шесть кнопок – три в группе Write и три в группе Read. Нажатие каждой кнопки в группе Write приведет к записи соответствующего значения в реестр, нажатие каждой кнопки в группе Read – к чтению этого значения.

Скачать исходный текст модуля, в котором содержатся обработчики нажатия кнопок, использующие методы класса TRegIniFile можно

Отметим, что рассмотренных выше функций вполне достаточно для того чтобы обеспечить минимальную функциональность приложения. Если же вам требуется читать и записывать данные из других секций реестра, вы можете воспользоваться методами класса TRegistry или непосредственно функциями Win32 API.

Класс TRegistry

Прежде чем рассмотреть пример использования свойств и методов класса TRegistry, давайте кратко перечислим их.

В следующей таблице перечислены свойства класса TRegistry.

Свойство

Описание

Позволяет узнать текущую подсекцию, в которой проводятся операции по чтению и записи. Для изменения подсекции следует использовать методы OpenKey и OpenKeyReadOnly

Позволяет узнать полное название текущей подсекции

Задает способ обновления информации в реестре – непосредственно или после вызова метода CloseKey.

Задает корневую секцию в реестре. По умолчанию установлено значение HKEY_CURRENT_USER

В следующей таблице перечислены методы класса TRegistry.

Свойство

Описание

Записывает внесенные изменения и закрывает текущую подсекцию

Создает экземпляр класса TRegistry и задает значение корневой секции - HKEY_CURRENT_USER

Создает подсекцию

Удаляет подсекцию

Удаляет значение элемента

Уничтожает ранее созданный экземпляр класса TRegistry

Возвращает размер данных для указанного элемента

Возвращает тип данных для указанного элемента

Возвращает информацию о текущем элементе

Возвращает имена подсекций для указанной секции

Возвращает названия элементов для указанной подсекции

Позволяет узнать, имеются ли подсекции для указанной секции

Позволяет узнать, существует ли элемент

Создает новую подсекцию и загружает в нее информацию из указанного файла

Перемещает указанную подсекцию и все вложенные подсекции в заданное место

Открывает подсекцию

Открывает подсекцию только для чтения

Считывает данные в бинарном формате

Считывает данные в булевом формате

Считывает данные в формате валюты

Считывает данные в формате даты

Считывает данные в формате "дата/время"

Считывает данные в формате с плавающей точкой

Считывает данные в целочисленном формате

Считывает данные в строчном формате

Считывает данные в формате времени

Устанавливает соединение с реестром на другом компьютере

Переименовывает элемент

Замещает значение элемента значениями из файла

Восстанавливает значение элемента из файла

Сохраняет значение элемента в файле

Удаляет подсекцию, загруженную методом LoadKey

Позволяет узнать, существует ли значение у элемента

Записывает данные в бинарном формате

Записывает данные в булевом формате

Записывает данные в формате валюты

Записывает данные в формате даты

Записывает данные в формате "дата/время"

WriteExpandString

Записывает данные в формате "расширенно" строки

Записывает данные в формате с плавающей точкой

Записывает данные в целочисленном формате

Записывает данные в строчном формате

Записывает данные в формате времени

→ Работа с реестром в 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);

MyKey: HKey; { Handle для работы с разделом }

Buffer: array of char; { Буфер }

Err, { Код ошибки }

index: longint; { Индекс подраздела }

Err:=RegOpenKey(HKEY_CLASSES_ROOT,"DelphiUnit",MyKey); { Открыли раздел }

if Err<> ERROR_SUCCESS then

MessageDlg("Нет такого раздела!!",mtError,,0);

{Определили имя первого подраздела }

Err:=RegEnumKey(MyKey,index,Buffer,Sizeof(Buffer));


Публикация компанией Dropbox кода Zulip – средства общения для IT-разработчиков

Одной из одобрительно встреченных программистами инициатив, реализующихся в рамках акции Hack Week, стала публикация исходного кода приложения Zulip – веб-приложения для общения между собой разработчиков в сфере IT-технологий.

Объединение ОС Android и Chrome

Слухи об объединении двух крупнейших ОС компании Google, Android и Chrome, гуляют по Интернету уже более 5 лет, но до сих пор этого не случилось, хотя очевидно, что с течением времени эти ОС становятся всё более похожими: так, в последнее время появилось немало Android-устройств, к которым прилагаются клавиатуры, а Chrome OS «научилась» работать с сенсорными экранами.

Конференция Linux Piter 2015

Уже почти через неделю в Санкт-Петербурге впервые в истории пройдёт конференция, посвящённая проблемам свободного программного обеспечения – Linux Piter 2015.

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 of char; { Буфер } Err, { Код ошибки } index: longint; { Индекс подраздела } begin Err:=RegOpenKey(HKEY_CLASSES_ROOT,"DelphiUnit",MyKey); { Открыли раздел } if Err<> ERROR_SUCCESS then begin MessageDlg("Нет такого раздела!!",mtError,,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);

ReadSectionValues(const Section: string; Strings: TStrings);

EraseSection(const Section: string);

Удалить раздел Section со всем содержимым

ReadBool(const Section, Ident: string; Default: Boolean): Boolean;

ReadInteger(const Section, Ident: string; Default: Longint): Longint;

ReadString(const Section, Ident, Default: string): string;

Закрыть и освободить ресурс. Необходимо вызвать при завершении работы с INI файлом

Property Values: 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;