2025-11-28 00:35:46 +09:00

360 lines
11 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Module Name:
regOps.h
Abstract:
Helper class to encapsulate registry operations.
--*/
#include <psapi.h>
namespace regfs {
#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383
// Represents a single entry in the registry, capturing its name and size.
struct RegEntry {
std::wstring Name;
ULONG Size;
};
// Stores RegEntry items for the entries within a registry key, separated into lists of subkeys
// and values.
struct RegEntries {
std::vector<RegEntry> SubKeys;
std::vector<RegEntry> Values;
};
class RegOps {
public:
RegOps()
{
_regRootKeyMap[L"HKEY_CLASSES_ROOT"] = HKEY_CLASSES_ROOT;
_regRootKeyMap[L"HKEY_CURRENT_USER"] = HKEY_CURRENT_USER;
_regRootKeyMap[L"HKEY_LOCAL_MACHINE"] = HKEY_LOCAL_MACHINE;
_regRootKeyMap[L"HKEY_USERS"] = HKEY_USERS;
_regRootKeyMap[L"HKEY_CURRENT_CONFIG"] = HKEY_CURRENT_CONFIG;
}
// Returns a RegEntries struct populated with the subkeys and values in the registry key whose
// path is specified.
HRESULT EnumerateKey(const std::wstring& path, RegEntries& entries)
{
HRESULT hr = S_OK;
if (PathUtils::IsVirtualizationRoot(path.c_str()))
{
// The path is the "root" of the registry, so return the names of the predefined keys
// in _regRootKeyMap.
for (auto it = _regRootKeyMap.begin(); it != _regRootKeyMap.end(); it++)
{
RegEntry entry;
entry.Name = it->first;
entries.SubKeys.emplace_back(entry);
}
}
else
{
// The path is somewhere below the root, so try opening the key.
HKEY subKey = nullptr;
hr = OpenKeyByPath(path, subKey);
// If the path corresponds to a registry key, enumerate it.
if (subKey != nullptr)
{
hr = EnumerateKey(subKey, entries);
RegCloseKey(subKey);
}
}
return hr;
}
// Reads a value from the registry.
bool ReadValue(const std::wstring& path, PBYTE data, UINT32& len)
{
auto lastPos = path.find_last_of(L"\\");
if (lastPos == std::wstring::npos)
{
// There are no '\' characters in the path. The only paths with no '\' are the predefined
// keys, so this can't be a value.
return false;
}
// Split the path into <key>\<value>
auto keyPath = path.substr(0, lastPos);
auto valName = path.substr(lastPos + 1);
// Open the key path to get a HKEY handle to it.
HKEY subkey = nullptr;
OpenKeyByPath(keyPath, subkey);
// Read the value's content from the registry.
DWORD ret = RegQueryValueEx(subkey,
valName.c_str(),
0,
nullptr,
reinterpret_cast<LPBYTE>(data),
reinterpret_cast<LPDWORD>(&len));
if (ret != ERROR_SUCCESS)
{
wprintf(L"%hs: RegQueryValueEx [%s]: %d\n",
__FUNCTION__, valName.c_str(), ret);
RegCloseKey(subkey);
return false;
}
RegCloseKey(subkey);
return true;
}
// Returns true if the given path corresponds to a key that exists in the registry.
bool DoesKeyExist(const std::wstring& path)
{
HKEY subkey = nullptr;
OpenKeyByPath(path, subkey);
if (subkey == nullptr)
{
wprintf(L"%hs: key [%s] doesn't exist \n",
__FUNCTION__, path.c_str());
return false;
}
RegCloseKey(subkey);
return true;
}
// Returns true if the given path corresponds to a value that exists in the registry, and tells
// you how big it is.
bool DoesValueExist(const std::wstring& path, INT64& valSize)
{
auto pos = path.find_last_of(L"\\");
if (pos == std::wstring::npos)
{
// There are no '\' characters in the path. The only paths with no '\' are the predefined
// keys, so this can't be a value.
return false;
}
else
{
HKEY subkey = nullptr;
OpenKeyByPath(path.substr(0, pos), subkey);
if (subkey == nullptr)
{
wprintf(L"%hs: value [%s] doesn't exist \n",
__FUNCTION__, path.substr(0, pos).c_str());
return false;
}
auto valPathStr = path.substr(pos + 1);
auto res = RegGetValue(subkey,
nullptr,
valPathStr.c_str(),
RRF_RT_ANY,
nullptr,
nullptr,
reinterpret_cast<PDWORD>(&valSize));
if (res != ERROR_SUCCESS)
{
wprintf(L"%hs: Could not get value [%s] at key [%s]: %d\n",
__FUNCTION__, valPathStr.c_str(), path.substr(0, pos).c_str(), res);
return false;
}
RegCloseKey(subkey);
}
return true;
}
private:
// Gets the HKEY for a registry key given the path, if it exists.
HRESULT OpenKeyByPath(const std::wstring& path, HKEY& hKey)
{
HRESULT hr = S_OK;
hKey = nullptr;
auto pos = path.find(L"\\");
if (pos == std::wstring::npos)
{
// There are no '\' characters in the path. The only paths with no '\' are the predefined
// keys, so try to find the correct HKEY in the predefined keys map.
if (_regRootKeyMap.find(path) != _regRootKeyMap.end())
{
hKey = _regRootKeyMap[path];
}
else
{
wprintf(L"%hs: root key [%s] doesn't exist\n",
__FUNCTION__, path.c_str());
hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
}
}
else
{
// The first component of the path should be a predefined key, so get its HKEY value and
// try opening the rest of the key relative to it.
auto rootKeyStr = path.substr(0, pos);
auto rootKey = _regRootKeyMap[rootKeyStr];
DWORD res = RegOpenKeyEx(rootKey,
path.substr(pos + 1).c_str(),
0,
KEY_READ,
&hKey);
if (res != ERROR_SUCCESS)
{
wprintf(L"%hs: failed to open key [%s]: %d\n",
__FUNCTION__, path.substr(pos + 1).c_str(), res);
hr = HRESULT_FROM_WIN32(res);
}
}
return hr;
}
// Returns a RegEntries struct populated with the subkeys and values in the specified registry key.
HRESULT EnumerateKey(HKEY hKey, RegEntries& entries)
{
HRESULT hr = S_OK;
DWORD subKeyCount = 0;
DWORD valueCount = 0;
DWORD i, retCode;
// Find out how many subkeys and values there are under this key.
retCode = RegQueryInfoKey(hKey,
nullptr,
nullptr,
nullptr,
&subKeyCount,
nullptr,
nullptr,
&valueCount,
nullptr,
nullptr,
nullptr,
nullptr);
if (retCode != ERROR_SUCCESS)
{
wprintf(L"%hs: RegQueryInfoKey: %d\n",
__FUNCTION__, retCode);
return HRESULT_FROM_WIN32(retCode);
}
TCHAR keyName[MAX_KEY_LENGTH];
DWORD keyNameLength;
// If there are subkeys, enumerate them until RegEnumKeyEx fails.
if (subKeyCount)
{
wprintf(L"\n%hs: Subkeys:\n",
__FUNCTION__);
for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
{
keyNameLength = MAX_KEY_LENGTH;
keyName[0] = '\0';
retCode = RegEnumKeyEx(hKey,
i,
keyName,
&keyNameLength,
nullptr,
nullptr,
nullptr,
nullptr);
if (retCode == ERROR_SUCCESS)
{
wprintf(TEXT("(%d) %s\n"), i + 1, keyName);
RegEntry entry;
entry.Name = std::wstring(keyName);
entry.Size = 0;
entries.SubKeys.push_back(entry);
}
else if (retCode != ERROR_NO_MORE_ITEMS)
{
wprintf(L"%hs: RegEnumKeyEx: %d\n",
__FUNCTION__, retCode);
hr = HRESULT_FROM_WIN32(retCode);
return hr;
}
}
}
TCHAR valueName[MAX_VALUE_NAME];
DWORD valueNameLength = MAX_VALUE_NAME;
// If there are values, enumerate them until RegEnumValue fails.
if (valueCount)
{
wprintf(L"\n%hs: Values: \n",
__FUNCTION__);
retCode = ERROR_SUCCESS;
for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
{
valueNameLength = MAX_VALUE_NAME;
valueName[0] = '\0';
DWORD size = 0;
retCode = RegEnumValue(hKey,
i,
valueName,
&valueNameLength,
nullptr,
nullptr,
nullptr,
&size);
if (retCode == ERROR_SUCCESS)
{
wprintf(TEXT("(%d) %s (%d bytes)\n"), i + 1, valueName, size);
RegEntry entry;
entry.Name = std::wstring(valueName);
entry.Size = size;
entries.Values.push_back(entry);
}
else if (retCode != ERROR_NO_MORE_ITEMS)
{
wprintf(L"%hs: RegEnumValue: %d\n",
__FUNCTION__, retCode);
hr = HRESULT_FROM_WIN32(retCode);
return hr;
}
}
}
return hr;
}
private:
// Maps string names of the predefined registry keys (HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, etc.)
// to their HKEY values.
std::map<std::wstring, HKEY> _regRootKeyMap;
};
}