2022-05-21 19:58:09 +02:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "RegistryKey.h"
|
|
|
|
|
|
|
|
namespace Win32
|
|
|
|
{
|
|
|
|
RegistryKey::RegistryKey(HKEY hKey, bool Writable, RegistryView View)
|
|
|
|
: RegistryKey(hKey, Writable, false, View)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
RegistryKey::RegistryKey(HKEY hKey, bool Writable, bool SystemKey, RegistryView View)
|
|
|
|
: _State(0), _Handle(hKey), _View(View), _KeyName("")
|
|
|
|
{
|
|
|
|
if (SystemKey)
|
|
|
|
this->_State |= RegistryKey::STATE_SYSTEMKEY;
|
|
|
|
if (Writable)
|
|
|
|
this->_State |= RegistryKey::STATE_WRITEACCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegistryKey::~RegistryKey()
|
|
|
|
{
|
|
|
|
this->Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RegistryKey::Close()
|
|
|
|
{
|
|
|
|
if (this->_Handle != nullptr && !this->IsSystemKey())
|
|
|
|
RegCloseKey(this->_Handle);
|
|
|
|
|
|
|
|
this->_Handle = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RegistryKey::Flush()
|
|
|
|
{
|
|
|
|
if (this->_Handle != nullptr && this->IsDirty())
|
|
|
|
RegFlushKey(this->_Handle);
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
RegistryKey RegistryKey::CreateSubKey(const String& SubKey)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
return this->CreateSubKeyInternal(SubKey);
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
void RegistryKey::DeleteSubKey(const String& SubKey, bool ThrowOnMissingSubKey)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
auto kPath = FixupName(SubKey); // Remove multiple slashes to a single slash
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto Key = this->InternalOpenSubKey(kPath, false);
|
|
|
|
if (Key.InternalSubKeyCount() > 0)
|
|
|
|
throw Win32Error::RegSubKeyChildren();
|
|
|
|
|
|
|
|
Key.Close();
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
if (ThrowOnMissingSubKey)
|
|
|
|
throw Win32Error::RegSubKeyMissing();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto dResult = RegDeleteKeyExA(this->_Handle, (const char*)kPath, (int)this->_View, NULL);
|
|
|
|
if (dResult != 0)
|
|
|
|
{
|
|
|
|
if (dResult == ERROR_FILE_NOT_FOUND && ThrowOnMissingSubKey)
|
|
|
|
throw Win32Error::RegSubKeyMissing();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
void RegistryKey::DeleteSubKeyTree(const String& SubKey, bool ThrowOnMissingSubKey)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
if (SubKey.Length() == 0 && IsSystemKey())
|
|
|
|
throw Win32Error::RegSubKeyMalformed();
|
|
|
|
|
|
|
|
auto kPath = FixupName(SubKey);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto Key = this->InternalOpenSubKey(kPath, false);
|
|
|
|
if (Key.InternalSubKeyCount() > 0)
|
|
|
|
{
|
|
|
|
auto SubKeyNames = this->InternalGetSubKeyNames();
|
|
|
|
|
|
|
|
for (auto& KeyName : SubKeyNames)
|
|
|
|
this->DeleteSubKeyTreeInternal(KeyName);
|
|
|
|
}
|
|
|
|
|
|
|
|
Key.Close();
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
if (ThrowOnMissingSubKey)
|
|
|
|
throw Win32Error::RegSubKeyMissing();
|
|
|
|
}
|
|
|
|
|
|
|
|
RegDeleteKeyExA(this->_Handle, (const char*)kPath, (int)this->_View, NULL);
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
void RegistryKey::DeleteValue(const String& Name, bool ThrowOnMissingSubKey)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
auto hResult = RegDeleteValueA(this->_Handle, (const char*)Name);
|
|
|
|
|
|
|
|
if (hResult == ERROR_FILE_NOT_FOUND || hResult == ERROR_FILENAME_EXCED_RANGE)
|
|
|
|
if (ThrowOnMissingSubKey)
|
|
|
|
throw Win32Error::RegSubKeyMissing();
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
RegistryKey RegistryKey::OpenSubKey(const String& Name, bool Writable)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
HKEY hHandle = nullptr;
|
|
|
|
auto hAccess = (Writable) ? (KEY_READ | KEY_WRITE) : KEY_READ;
|
|
|
|
auto kPath = FixupName(Name);
|
|
|
|
auto hResult = RegOpenKeyExA(this->_Handle, (const char*)kPath, NULL, (hAccess | (int)this->_View), &hHandle);
|
|
|
|
|
|
|
|
if (hResult == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
auto Result = RegistryKey(hHandle, Writable, this->_View);
|
|
|
|
Result._KeyName = this->_KeyName + "\\" + kPath;
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
throw Win32Error::SystemError(GetLastError());
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
List<String> RegistryKey::GetValueNames()
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
auto nValues = this->InternalValueCount();
|
2022-05-21 21:51:35 +02:00
|
|
|
auto Result = List<String>();
|
2022-05-21 19:58:09 +02:00
|
|
|
|
|
|
|
for (uint32_t i = 0; i < nValues; i++)
|
|
|
|
{
|
|
|
|
char NameBuffer[MaxKeyLength + 1]{};
|
|
|
|
uint32_t NameLength = (MaxKeyLength + 1);
|
|
|
|
|
|
|
|
auto hResult = RegEnumValueA(this->_Handle, i, NameBuffer, (LPDWORD)&NameLength, NULL, NULL, NULL, NULL);
|
|
|
|
if (hResult == ERROR_SUCCESS)
|
|
|
|
Result.EmplaceBack(NameBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
RegistryValueType RegistryKey::GetValueKind(const String& Name)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
DWORD Type = 0, DataSize = 0;
|
|
|
|
auto qResult = RegQueryValueExA(this->_Handle, (const char*)Name, NULL, &Type, NULL, &DataSize);
|
|
|
|
|
|
|
|
switch (Type)
|
|
|
|
{
|
|
|
|
case REG_DWORD:
|
|
|
|
return RegistryValueType::Dword;
|
|
|
|
case REG_DWORD_BIG_ENDIAN:
|
|
|
|
return RegistryValueType::DwordBigEndian;
|
|
|
|
case REG_SZ:
|
|
|
|
return RegistryValueType::String;
|
|
|
|
case REG_MULTI_SZ:
|
|
|
|
return RegistryValueType::MultiString;
|
|
|
|
case REG_BINARY:
|
|
|
|
return RegistryValueType::Binary;
|
|
|
|
case REG_LINK:
|
|
|
|
return RegistryValueType::SymbolicLink;
|
|
|
|
case REG_RESOURCE_LIST:
|
|
|
|
return RegistryValueType::ResourceList;
|
|
|
|
case REG_FULL_RESOURCE_DESCRIPTOR:
|
|
|
|
return RegistryValueType::FullResourceDescriptor;
|
|
|
|
case REG_QWORD:
|
|
|
|
return RegistryValueType::Qword;
|
|
|
|
case REG_RESOURCE_REQUIREMENTS_LIST:
|
|
|
|
return RegistryValueType::ResourceRequirementsList;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RegistryValueType::None;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t RegistryKey::GetSubKeyCount()
|
|
|
|
{
|
|
|
|
return this->InternalSubKeyCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t RegistryKey::GetValueCount()
|
|
|
|
{
|
|
|
|
return this->InternalValueCount();
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
List<String> RegistryKey::GetSubKeyNames()
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
return this->InternalGetSubKeyNames();
|
|
|
|
}
|
|
|
|
|
|
|
|
RegistryKey RegistryKey::OpenBaseKey(RegistryHive Hive, RegistryView View)
|
|
|
|
{
|
|
|
|
auto Index = ((int)Hive) & 0x0FFFFFFF;
|
|
|
|
auto Key = RegistryKey((HKEY)Hive, true, true, View);
|
|
|
|
|
|
|
|
Key._KeyName = RegistryKey::HiveNames[Index];
|
|
|
|
|
|
|
|
return Key;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegistryKey RegistryKey::FromHandle(HKEY hKey, RegistryView View)
|
|
|
|
{
|
|
|
|
return RegistryKey(hKey, true, View);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RegistryKey::IsDirty()
|
|
|
|
{
|
|
|
|
return (this->_State & RegistryKey::STATE_DIRTY) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RegistryKey::IsSystemKey()
|
|
|
|
{
|
|
|
|
return (this->_State & RegistryKey::STATE_SYSTEMKEY) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RegistryKey::IsWritable()
|
|
|
|
{
|
|
|
|
return (this->_State & RegistryKey::STATE_WRITEACCESS) != 0;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
RegistryKey RegistryKey::CreateSubKeyInternal(const String& SubKey)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
auto kPath = FixupName(SubKey); // Remove multiple slashes to a single slash
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Test if the key already exists
|
|
|
|
return RegistryKey::InternalOpenSubKey(kPath, this->IsWritable());
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
// Doesn't exist, can be created
|
|
|
|
HKEY hHandle = nullptr;
|
|
|
|
DWORD Disposition = 0;
|
|
|
|
auto hResult = RegCreateKeyExA(this->_Handle, (const char*)kPath, NULL, NULL, REG_OPTION_NON_VOLATILE, ((KEY_READ | KEY_WRITE) | (int)this->_View), NULL, &hHandle, &Disposition);
|
|
|
|
|
|
|
|
if (hResult == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
auto nKey = RegistryKey(hHandle, true, this->_View);
|
|
|
|
|
|
|
|
if (kPath.Length() == 0)
|
|
|
|
nKey._KeyName = _KeyName;
|
|
|
|
else
|
|
|
|
nKey._KeyName = _KeyName + "\\" + kPath;
|
|
|
|
|
|
|
|
return nKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
throw Win32Error::SystemError(GetLastError());
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
void RegistryKey::DeleteSubKeyTreeInternal(const String& SubKey)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto Key = this->InternalOpenSubKey(SubKey, true);
|
|
|
|
if (Key.InternalSubKeyCount() > 0)
|
|
|
|
{
|
|
|
|
auto SubKeyNames = Key.InternalGetSubKeyNames();
|
|
|
|
|
|
|
|
for (auto& KeyName : SubKeyNames)
|
|
|
|
Key.DeleteSubKeyTreeInternal(KeyName);
|
|
|
|
}
|
|
|
|
|
|
|
|
Key.Close();
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
// Nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
RegDeleteKeyExA(this->_Handle, (const char*)SubKey, (int)this->_View, NULL);
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
RegistryKey RegistryKey::InternalOpenSubKey(const String& Name, bool Writable)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
HKEY hHandle = nullptr;
|
|
|
|
auto hAccess = (Writable) ? (KEY_READ | KEY_WRITE) : KEY_READ;
|
|
|
|
auto hResult = RegOpenKeyExA(this->_Handle, (const char*)Name, NULL, (hAccess | (int)this->_View), &hHandle);
|
|
|
|
|
|
|
|
if (hResult == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
auto Result = RegistryKey(hHandle, Writable, this->_View);
|
|
|
|
Result._KeyName = this->_KeyName + "\\" + Name;
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
throw Win32Error::SystemError(GetLastError());
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
std::unique_ptr<uint8_t[]> RegistryKey::InternalGetValue(const String& Name, uint64_t& ValueSize)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
DWORD Type = 0, DataSize = 0;
|
|
|
|
auto qResult = RegQueryValueExA(this->_Handle, (const char*)Name, NULL, &Type, NULL, &DataSize);
|
|
|
|
|
|
|
|
if (qResult != ERROR_SUCCESS)
|
|
|
|
throw Win32Error::SystemError(GetLastError());
|
|
|
|
|
|
|
|
auto ResultBuffer = std::make_unique<uint8_t[]>(DataSize);
|
|
|
|
RegQueryValueExA(this->_Handle, (const char*)Name, NULL, &Type, ResultBuffer.get(), &DataSize);
|
|
|
|
|
|
|
|
ValueSize = DataSize;
|
|
|
|
|
|
|
|
return ResultBuffer;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
void RegistryKey::InternalSetValue(const String& Name, uint32_t ValueType, uint8_t* Buffer, uint64_t BufferSize)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
auto hResult = RegSetValueExA(this->_Handle, (const char*)Name, NULL, ValueType, Buffer, (DWORD)BufferSize);
|
|
|
|
if (hResult != ERROR_SUCCESS)
|
|
|
|
throw Win32Error::SystemError(GetLastError());
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t RegistryKey::InternalSubKeyCount()
|
|
|
|
{
|
|
|
|
DWORD SubKeys = 0, Junk = 0;
|
|
|
|
RegQueryInfoKeyA(this->_Handle, NULL, NULL, NULL, &SubKeys, NULL, NULL, &Junk, NULL, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
return (uint32_t)SubKeys;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t RegistryKey::InternalValueCount()
|
|
|
|
{
|
|
|
|
DWORD Values = 0, Junk = 0;
|
|
|
|
RegQueryInfoKeyA(this->_Handle, NULL, NULL, NULL, &Junk, NULL, NULL, &Values, NULL, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
return (uint32_t)Values;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
List<String> RegistryKey::InternalGetSubKeyNames()
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
2022-05-21 21:51:35 +02:00
|
|
|
auto Result = List<String>();
|
2022-05-21 19:58:09 +02:00
|
|
|
auto sCount = this->InternalSubKeyCount();
|
|
|
|
|
|
|
|
char Buffer[RegistryKey::MaxKeyLength + 1]{};
|
|
|
|
DWORD NameLength = RegistryKey::MaxKeyLength + 1;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < sCount; i++)
|
|
|
|
{
|
|
|
|
NameLength = RegistryKey::MaxKeyLength + 1;
|
|
|
|
auto hQuery = RegEnumKeyExA(this->_Handle, i, Buffer, &NameLength, NULL, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (hQuery == 0)
|
|
|
|
Result.EmplaceBack(Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
String RegistryKey::FixupName(String Name)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
RegistryKey::FixupPath(Name);
|
|
|
|
|
|
|
|
auto eChar = Name.Length() - 1;
|
|
|
|
if (eChar >= 0 && Name[eChar] == '\\')
|
2022-05-21 21:51:35 +02:00
|
|
|
return Name.SubString(0, eChar);
|
2022-05-21 19:58:09 +02:00
|
|
|
|
|
|
|
return Name;
|
|
|
|
}
|
|
|
|
|
2022-05-21 21:51:35 +02:00
|
|
|
void RegistryKey::FixupPath(String& Path)
|
2022-05-21 19:58:09 +02:00
|
|
|
{
|
|
|
|
// Replace double slash with single slashes
|
|
|
|
Path = Path.Replace("\\\\", "\\");
|
|
|
|
}
|
|
|
|
}
|