Для удаления ключей из реестра предназначена функция RegDeleteKey из Win32 API. В качестве параметров эта функция получает дескриптор родительского ключа, а также имя подключа, подлежащего удалению. В качестве дескриптора родительского ключа можно передать константу, соответствующую одному из основных разделов реестра (HKEY_CLASSES_ROOT, HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER и т. п.), а также любой другой дескриптор, полученный в результате вызова функции RegOpenKey(Ex).
В качестве примера рассмотрим код, удаляющий ключ "Some key" из раздела HKEY_LOCAL_MACHINE.
RegDeleteKey(HKEY_LOCAL_MACHINE, "Some key");
|
Функция RegDeleteKey удобна, но имеет один серьёзный недостаток: под Windows NT/2000 она удаляет из реестра только пустые ключи, то есть ключи, не содержащие подключей.
Альтернативой RegDeleteKey является функция SHDeleteKey из shell API (объявлена в файле shlwapi.h). Она используется в точности так же, как и RegDeleteKey, например:
#include <shlwapi.h> #pragma comment(lib,"shlwapi.lib") ... SHDeleteKey(HKEY_LOCAL_MACHINE, "Some key"); |
Функция SHDeleteKey корректно удаляет непустые ключи из реестра как под Windows 9x, так и под Windows NT/2000, но, к сожалению, при её использовании возникает другая проблема: она появилась в библиотеке shlwapi.dll только начиная с версии 4.71. А это означает, что функция SHDeleteKey будет доступна под Windows 95 и Windows NT только при наличии Internet Explorer версии 4.0 и выше.
Если прямое применение функций RegDeleteKey и SHDeleteKey не возможно, остаётся применить стандартный в таких случаях подход: написать свою функцию, которая будет удалять сначала все подключи некоторого ключа, я затем и сам ключ. Алгоритм работы этой функции может выглядеть примерно так: получаем список всех подключей заданного, рекурсивно вызываем для каждого из них нашу функцию удаления, а затем удаляем сам ключ при помощи RegDeleteKey.
Вот один из возможных вариантов функции, рекурсивно удаляющей ключ вместе со всеми подключами.
LONG DeleteKey(HKEY hParentKey, LPCTSTR szKey) { TCHAR *szSubKey = NULL; HKEY hKey = NULL; LONG nRes; __try { nRes = RegOpenKeyEx(hParentKey, szKey, 0, KEY_ENUMERATE_SUB_KEYS|KEY_READ | KEY_WRITE, &hKey); if(nRes != ERROR_SUCCESS) __leave; DWORD nMaxLen; RegQueryInfoKey( hKey, NULL, NULL, NULL, NULL, &nMaxLen, NULL, NULL, NULL, NULL, NULL, NULL); nMaxLen++; szSubKey = new TCHAR[nMaxLen]; DWORD nSize = nMaxLen; FILETIME tTime; while((nRes=RegEnumKeyEx( hKey, 0, szSubKey, &nSize, 0, NULL, NULL, &tTime)) == ERROR_SUCCESS) { nRes = DeleteKey(hKey, szSubKey); if(nRes != ERROR_SUCCESS) __leave; nSize = nMaxLen; } nRes = RegDeleteKey(hParentKey, szKey); } __finally { if(szSubKey != NULL) delete [] szSubKey; if(hKey != NULL) RegCloseKey(hKey); return nRes; } } |
Если эта функция кажется вам слишком сложной, вам будет приятно узнать, что Microsoft уже написала её за вас. Соответствующая функция называется RecurseDeleteKey и является членом класса CRegKey из библиотеки ATL. Пример её использования приведён ниже.
#include <atlbase.h> ... CRegKey rKey; rKey.Attach(HKEY_LOCAL_MACHINE); rKey.RecurseDeleteKey("Some key"); |
Хотя класс CRegKey входит в библиотеку ATL, он целиком реализован в заголовочном файле atlbase.h и не использует ссылается на другие классы ATL. Поэтому его использование не приведёт к "раздуванию" кода вашей программы. Следует, однако, иметь в виду, что в функции RecurseDeleteKey на имя подключа выделяется ровно 256 байт, что теоретически может привести к проблемам под Windows NT/2000, где длина имени ключа может быть и больше. Хотя на практике такие длинные ключи практически никогда не встречаются.
Описанных способов оказывается вполне достаточно, чтобы решить поставленную задачу.