Ptz управление с пк. Интеллектуализация купольной поворотной камеры: автоматическое патрулирование, выбор целей и слежение

Реестр Windows является неотъемлемой частью каждой операционной системы Microsoft Windows. Он действует так, же как каталог, в котором хранятся все виды пользовательских настроек, конфигурационных данных о приложениях, файловые ассоциации и т.д. Если попробовать дать определение этого чудо-компонента, то реестр - компонент операционной системы компьютера, который в иерархической базе данных хранит важнейшие установки и информацию о приложениях, системных операциях и пользовательской конфигурации. Таким образом, возможность работы с реестром – это что-то, что не может быть упущено из виду разработчиком Windows приложений.

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

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

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

Структура реестра

Важно понять структуру реестра на данном этапе усваивания материала, что бы потом у нас не возникло непонимания по ходу дальнейшего изучения. В этом разделе мы очень быстро и кратко «пробежимся» по реестру, т.к. на подробное его изучение потребуется много времени и места. Представьте реестр как папку. В ней могут быть другие папки и файлы. Теперь разберемся с обозначением. Реестр Windows содержит два элемента: раздел (key) и значение (value). В нашей аналогии разделы выступают в роли папок, в то время как значения – файлы. В действительности, значения – это пары «имя-данные». Это значит, что значение делится на две части: имя и данные. Имя используется как идентификатор, а данные как часть фактических данных. Каждый раздел имеет значение, но, помимо значения, раздел может иметь и подраздел. Весь реестр делится на логические разделы, которые называются «ульи» (hives). Всего таких разделов пять.

Теперь зайдите в редактор реестра (Пуск-Выполнить-regedit) и посмотрите его структуру. На всякий случай сделайте копию реестра. Хотя наша программа будет безобидной для него, лишним это действие все равно не будет. Для тех, кто не знает, я расскажу, как сделать копию реестра.

Что бы сделать backup своего реестра выполните следующие действия:
1) Нажмите "Пуск", "Выполнить" и введите "regedit".
2) Появится окно редактора реестра. Нажмите в верхней части окна "Файл", потом "Экспорт". Введите любое имя для сохраняемого резервного файла реестра, тип файла выберите "Файлы реестра *.reg". Ниже, под надписью "Диапазон экспорта" выберите "Весь реестр", нажмите "Сохранить".

Теперь разберем некоторые функции, которые нам понадобятся для написания задуманного.

Базовые функции реестра

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

Наша первая функция - RegOpenKeyEx (). Эта функция открывает указанный раздел реестра и возвращает ERROR_SUCCESS при успешном выполнении. Важно понять, что эта функция открывает уже существующий раздел; она не создаст новый раздел, если такового не существует.

Вторая функция, которую мы будем использовать – это функция RegSetValueEx(), которая создает новое значение в нашем разделе, открытом с помощью первой рассмотренной функции.

Следующие три функции позволят добавить новый раздел и удалить данные с реестра. RegCreateKeyEx () будет использоваться для создания нового ключа, а при удалении значения и ключа мы будем вызывать RegDeleteValue () и RegDeleteKey () соответственно. Если Вы пользователь Windows Vista или Microsoft Server 2008, то вместо функции RegDeleteValue () Вам следует вызвать функцию RegDeleteTree(). Хотя чаще возникает потребность писать универсальное приложение, которое будет работать с любым продуктом Microsoft. Поэтому делайте проверку WINWER в своем коде.

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

Как понятно из названия данного раздела, тут будет код нашей программы. Но перед тем, как писать код необходимо создать пустое консольное приложение. Я использую Microsoft Visual Studio 2010. О том, как создать, необходимый нам, тип приложения подробно описано в последнем номере журнала () в статье "Что нам стоит GUI построить".

Тут я приведу сразу весь код, а потом прокомментирую его, дав подробное описание каждой функции.
int main()
{
HKEY hKey;
DWORD dwDisposition;
unsigned char szStr;
szStr="1"; szStr="\0";

if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\VR_Online\\Test"), 0, KEY_ALL_ACCESS, &hKey)!=ERROR_SUCCESS)
cout<<"\nError opening the desired subkey (doesn"t exist?).\n";
else
{

cout<<"\nThe value of the key was set successfully.\n";
else
cout<<"\nError setting the value of the key.\n";
}
RegCloseKey(hKey);

RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\VR_Online\\Test\\Another SubKey"), 0, NULL, 0, 0, NULL, &hKey, &dwDisposition);
if (dwDisposition != REG_CREATED_NEW_KEY && dwDisposition != REG_OPENED_EXISTING_KEY)
cout<<"\nError creating the desired subkey (permissions?).\n";
else
cout<<"\nThe subkey was successfully created.\n";
RegCloseKey(hKey);


{

cout<<"\nString Value value successfully removed.\n";
else
cout<<"\nError removing the specified value (permissions?).\n";
}
else
cout<<"\nError opening the specified subkey path (doesn"t exist?).\n";

RegCloseKey(hKey);

if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\VR_Online\\Test"), 0, KEY_ALL_ACCESS, &hKey)==ERROR_SUCCESS)
{

cout<<"\nAnother SubKey key successfully removed.\n";
else
cout<<"\nError removing the specified key (permissions?).\n";
}
else
cout<<"\nError opening the specified subkey path (doesn"t exist?).\n";

RegCloseKey(hKey);


{

cout<<"\nTest key successfully removed.\n";
else
cout<<"\nError removing the specified key (permissions?).\n";
}
else
cout<<"\nError opening the specified subkey path (doesn"t exist?).\n";

RegCloseKey(hKey);


{

cout<<"\nVR_Online key successfully removed.\n";
else
cout<<"\nError removing the specified key (permissions?).\n";
}
else
cout<<"\nError opening the specified subkey path (doesn"t exist?).\n";

RegCloseKey(hKey);

Ну, что же, теперь надо разобраться, что тут написано.
HKEY hKey;
DWORD dwDisposition;
unsigned char szStr;
szStr="1"; szStr="\0";

В первой строке мы объявили переменную hKey, типа HKEY. Это переменная – дескриптор указанного «улья» реестра. Во второй строке объявлена переменная, dwDisposition, которая нужна для определения, является ли подраздел созданным или он уже существовал, и может ли он быть открыт успешно. Данная переменная понадобится нам для функции RegCreateKeyEx (). Подробно о значениях, которые функция загоняет в эту переменную, Вы сможете узнать на msdn.com в описании данной функции. Далее мы объявили массив типа unsigned char, состоящий из двух элементов. Первому элементу мы присвоили значение «1», а второму – конец строки. Эта переменная (массив) будет служить данными для нашего имени при создании нового значения функцией RegSetValueEx().
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\VR_Online\\Test"), 0, KEY_ALL_ACCESS, &hKey)!=ERROR_SUCCESS)
cout<<"\nError opening the desired subkey (doesn"t exist?).\n";
else
{
if (RegSetValueEx(hKey, TEXT("String Value"), NULL, REG_SZ, szStr, sizeof(szStr))==ERROR_SUCCESS)
cout<<"\nThe value of the key was set successfully.\n";
else
cout<<"\nError setting the value of the key.\n";
}
RegCloseKey(hKey);

В вышеприведенном куске кода мы проверяем успешное выполнение функции RegOpenKeyEx(). Описание этой функции приведено выше. Т.к. эта функция открывает уже существующий раздел то, выполнение этой функции выдаст нам сообщение об ошибке. Что бы этого избежать, можно создать «вручную» этот раздел, а можно и программно. Давайте создадим его «вручную», т.к. далее вы узнаете, как создавать разделы программно. Что бы «вручную» создать раздел, необходимо войти в редактор реестра (Пуск-Выполнить-regedit), выбрать нужным нам «улей» (в нашем случае HKEY_LOCAL_MACHINE). В нем выбираем раздел «SOFTWARE» (кстати, в нашей функции, как и во всех функциях работы с реестром регистр букв не важен), жмем на него правой клавишей мыши и «Создать»-«Раздел». Присваиваем разделу имя VR_Online, а потом в нем создаем подраздел с именем «Test» аналогичным образом.

Первый параметр функции – раздел реестра, который мы хотим открыть. Второй – имя подраздела. В данном примере мы открыли подраздел “SOFTWARE” По поводу третьего параметра документация Microsoft говорит только то, что он зарезервирован и должен быть равным нулю. Четвертый параметр – уровень доступа. В данном примере мы получили полный доступ к этому разделу. Однако не всегда раздел позволят получить к нему полный доступ, в таком случае функция будет выполнена неудачно. Последний параметр этой функции – указатель на переменную, которой будет передан дескриптор открытого раздела.

Если раздел существует, то мы устанавливаем ему значение (помните я говорил, что значение есть пара «имя-данные»?). Именем значения будет «String Value», а данными – наш массив szStr. Создаем мы значение с помощью функции RegSetValueEx(),в которую последовательно передаем дескриптор раздела, название переменной, тип данных (с типами данных Вы можете ознакомиться на msdn - http://msdn.microsoft.com/en-us/library/ms724884 (v=vs.85).aspx), сейчас только скажу, что этот тип значит строковую переменную. Последние два параметра – указатель на буфер данных и его размер. О результате выполнения этой функции на экран выводится сообщение. В конце мы вызываем функцию RegCloseKey().

Далее мы программно создадим подраздел. Делается это с помощью функции RegCreateKeyEx ().
RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\VR_Online\\Test\\Another SubKey"), 0, NULL, 0, 0, NULL, &hKey, &dwDisposition);

if (dwDisposition != REG_CREATED_NEW_KEY && dwDisposition != REG_OPENED_EXISTING_KEY)
cout<<"\nError creating the desired subkey (permissions?).\n";
else
cout<<"\nThe subkey was successfully created.\n";
RegCloseKey(hKey);

Первые два параметра, а так же предпоследний параметр, понятны исходя из уже известного материала. Про последний параметр я рассказал выше, при описании, объявленных в начале функции main(), переменных. Третий параметр зарезервирован и должен равняться нулю. Четвертый – тип класса раздела. В пятом параметре могут содержаться дополнительные опции, значение которых можно глянуть в описании этой функции на msdn. Следующий параметр определяет спецификатор доступа к данному разделу. Седьмой параметр является атрибутом безопасности. Он определяет, может ли данный раздел (а точнее его дескриптор) наследоваться дочерными процессами. Если он в значении NULL, то дескриптор не может быть унаследован.

А теперь очистим наш реестр от всего того, что мы создали.
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\VR_Online\\Test"), 0, KEY_ALL_ACCESS, &hKey)==ERROR_SUCCESS)
{
if (RegDeleteValue(hKey, TEXT("String Value"))==ERROR_SUCCESS)
cout<<"\nString Value value successfully removed.\n";
else
cout<<"\nError removing the specified value (permissions?).\n";
}
else
cout<<"\nError opening the specified subkey path (doesn"t exist?).\n";

RegCloseKey(hKey);

if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\VR_Online\\Test"), 0, KEY_ALL_ACCESS, &hKey)==ERROR_SUCCESS)
{
if (RegDeleteKey(hKey, TEXT("Another SubKey"))==ERROR_SUCCESS)
cout<<"\nAnother SubKey key successfully removed.\n";
else
cout<<"\nError removing the specified key (permissions?).\n";
}
else
cout<<"\nError opening the specified subkey path (doesn"t exist?).\n";

RegCloseKey(hKey);

if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\VR_Online"), 0, KEY_ALL_ACCESS, &hKey)==ERROR_SUCCESS)
{
if (RegDeleteKey(hKey, TEXT("Test"))==ERROR_SUCCESS)
cout<<"\nTest key successfully removed.\n";
else
cout<<"\nError removing the specified key (permissions?).\n";
}
else
cout<<"\nError opening the specified subkey path (doesn"t exist?).\n";

RegCloseKey(hKey);

if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software"), 0, KEY_ALL_ACCESS, &hKey)==ERROR_SUCCESS)
{
if (RegDeleteKey(hKey, TEXT("VR_Online"))==ERROR_SUCCESS)
cout<<"\nVR_Online key successfully removed.\n";
else
cout<<"\nError removing the specified key (permissions?).\n";
}
else
cout<<"\nError opening the specified subkey path (doesn"t exist?).\n";

RegCloseKey(hKey);

Что ж…тут только две новых функции: RegDeleteValue() и RegDeleteKey(). Их назначение понятно из их названий, а параметры понятны из усвоенного материала и простой интуиции. Как Вы могли заметить, эта часть кода обладает значительным минусом – нельзя удалить сразу раздел VR_Online со всем его содержимым. Удалять надо, начиная с «глубин» подраздела. Но заинтересовавшиеся читатели могут попробовать написать рекурсивную функцию, которая сама будет это делать.

Я вот еще раз перечитал свою статью и понял, что чего-то тут не хватает. Дело в том, что чаще приходится использовать данные реестра, а не изменять их или добавлять данные в реестр. Поэтому, как бонус, тем, кто дочитал до этого места, я рассажу, как с помощью реестра получить адрес стартовой страницы Internet Explorer, а затем изменить его. И хотя этим браузером мало кто пользуется, технология получения подобной информации одинакова. Для начала установим значение стартовой страницы. Сделать это можно тремя способами: через редактор реестра вручную, через браузер и программно. Т.к. наша тема связана с реестром, а программно мы изменим значение позже, то сейчас мы это сделаем вручную.

Заходим в «Пуск» - «Выполнить» и пишем regedit. В редакторе реестра проходи по пути «Software\\Microsoft\\Internet Explorer\\Main» и находим там значение Start Page. Жмем на эту переменную два раза и в появившемся диалоговом окне в поле «значение» указываем, например, «http://google.com”.

Следующий код Вы можете использовать как раз для достижения нашей «бонусной» цели.
TCHAR lpData={0};
DWORD buffersize = sizeof(lpData);

If (RegOpenKeyEx (HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Main"),NULL,KEY_READ,&hKey)==ERROR_SUCCESS)
{
if (RegQueryValueEx(hKey,TEXT("Start Page"),NULL,NULL,(LPBYTE) lpData,&buffersize)==ERROR_SUCCESS)
{
cout<<"\nYour current Internet start page is ";
wcout< }
else
cout<<"\nError getting the specified value.\n"
}
else
cout<<"\nError opening the specified subkey path (doesn"t exist?).\n";

RegCloseKey (hKey);

TCHAR *Val=_T("http://сайт");
DWORD size=_tcslen(Val);

if (RegOpenKeyEx (HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Main"),NULL,KEY_ALL_ACCESS,&hKey)==ERROR_SUCCESS)
{
if (RegSetValueEx(hKey, TEXT("Start Page"),0, REG_SZ, (BYTE*)Val,2*size)==ERROR_SUCCESS)
{
cout<<"\nNow your Internet start page is ";
wcout< }
else
cout<<"\nError setting the value of the key.\n";
}
else
cout<<"\nError opening the specified subkey path (doesn"t exist?).\n";

RegCloseKey (hKey);

Как видно из кода, у нас только одна неизвестная нам функция. RegQueryValueEx(). Она позволяет получить значение, которое хранится в указанном разделе. Первые два параметра этой функции, я думаю, не стоит описывать. Третий зарезервирован. Четвертый параметр содержит тип получаемого значения. Два последних параметра определяют буфер, в который будет записано значение, и его размер соответственно. Ну а далее мы изменяем значение этой переменной с помощью,уже известной нам, функции.

Что бы Вам было более ясно происходящее в данном коде, я расскажу Вам о типах char, TCHAR и о кодировке UNICODE.

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

Тип char используется для ANSI строк, т.е. строк, символы которых занимают один байт (8 бит). То есть допускается всего 256 (2 в восьмой степени) символов. Гляньте в таблицу ASCII, и Вы увидите, что все символы там не выходят за значение 255. Этого количества символов хватает нам с Вами с нашим-то алфавитом. И тип char идеально подходит для содержания этих символов.

Но давайте подумаем о японцах. У них существуют различные наборы символов, такие как, например катакана (katakana), хирагана (hiragana), канжи (kanji) и ромаджи (romaji). Невозможно впихнуть все эти символы в диапазоне от нуля до 255. Поэтому и используется кодировка Unicode, которая может содержать 65535 (2 в шестнадцатой степени) символов.

В основном тип TCHAR и используется для описания Unicode строк. В отличие от типа char, tchar занимает 2 байта. Это и объясняет умножение на двойку длины строки, в которой содержится новое имя стартовой страницы.
if (RegSetValueEx(hKey, TEXT("Start Page"),0, REG_SZ, (BYTE*)Val,2*size)==ERROR_SUCCESS)

Т.к. продукты Microsoft используют по всему миру, то программисты этой компании потрудились над тем, что бы разработчикам приложений под их основной продукт было удобно пользоваться своим языком, а не вездесущим английским. Поэтому почти все API функции «зависят» от Unicode.
Для удобной работы с Unicode – строками существует файл tchar.h. В нем собрано огромное количество макросов для работы TCHAR. Макрос TEXT, взятый как раз из этой библиотеки, позволяет компилировать программу и под Unicode и под ANSI. Так же там описан оператор wcout, который работает аналогично cout, но для TCHAR-типа.
Я думаю, что материал этого раздела хоть как-то пролил свет на Ваше представление о происходящем.

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

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

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

Спасибо за внимание.

Written by: Сергей Дубовик aka SD
E-mail: eval(unescape("%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%73%64%62%6f%78%40%74%75%74%2e%62%79%22%3e%73%64%62%6f%78%40%74%75%74%2e%62%79%3c%2f%61%3e%27%29%3b"))