Determine path to registry key from HKEY handle in C++
Use LoadLibrary
and NtQueryKey
exported function as in the following code snippet.
#include <windows.h>
#include <string>
typedef LONG NTSTATUS;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
#ifndef STATUS_BUFFER_TOO_SMALL
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#endif
std::wstring GetKeyPathFromKKEY(HKEY key)
{
std::wstring keyPath;
if (key != NULL)
{
HMODULE dll = LoadLibrary(L"ntdll.dll");
if (dll != NULL) {
typedef DWORD (__stdcall *NtQueryKeyType)(
HANDLE KeyHandle,
int KeyInformationClass,
PVOID KeyInformation,
ULONG Length,
PULONG ResultLength);
NtQueryKeyType func = reinterpret_cast<NtQueryKeyType>(::GetProcAddress(dll, "NtQueryKey"));
if (func != NULL) {
DWORD size = 0;
DWORD result = 0;
result = func(key, 3, 0, 0, &size);
if (result == STATUS_BUFFER_TOO_SMALL)
{
size = size + 2;
wchar_t* buffer = new (std::nothrow) wchar_t[size/sizeof(wchar_t)]; // size is in bytes
if (buffer != NULL)
{
result = func(key, 3, buffer, size, &size);
if (result == STATUS_SUCCESS)
{
buffer[size / sizeof(wchar_t)] = L'\0';
keyPath = std::wstring(buffer + 2);
}
delete[] buffer;
}
}
}
FreeLibrary(dll);
}
}
return keyPath;
}
int _tmain(int argc, _TCHAR* argv[])
{
HKEY key = NULL;
LONG ret = ERROR_SUCCESS;
ret = RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft", &key);
if (ret == ERROR_SUCCESS)
{
wprintf_s(L"Key path for %p is '%s'.", key, GetKeyPathFromKKEY(key).c_str());
RegCloseKey(key);
}
return 0;
}
This will print the key path on the console:
Key path for 00000FDC is
'\REGISTRY\MACHINE\SOFTWARE\Microsoft'.
How to extract hive and registry name from registry key
If I understand you correctly, you just want to split the string "HKEY_LOCAL_MACHINE\SOFTWARE\Mozilla\Firefox"
into substrings "HKEY_LOCAL_MACHINE"
and "SOFTWARE\Mozilla\Firefox"
. There are no Win32 API functions for that exact purpose, but you can use the find()
and substr()
methods of C++'s std::wstring
class, eg:
#include <string>
std::wstring keyname = ...; // "HKEY_LOCAL_MACHINE\\SOFTWARE\\Mozilla\\Firefox"
std::wstring::size_type pos = keyname.find(L'\\');
if (pos != std::wstring::npos)
{
std::wstring root = keyname.substr(0, pos);
std::wstring key = keyname.substr(pos+1);
// use root and key as needed...
}
Alternative, you can use std::wistringstream
and std::getline()
:
#include <string>
#include <sstream>
std::wstring keyname = ...; // "HKEY_LOCAL_MACHINE\\SOFTWARE\\Mozilla\\Firefox"
std::wstring root, key;
std::wistringstream iss(keyname);
if (std::getline(iss, root, L'\\') && std::getline(iss, key))
{
// use root and key as needed...
}
How to get every key and subkey from registry?
The first thing to do is get rid of those globals; they're just complicating things. With recursion you want everything on the stack. The code below fixes your problem.
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383
void test( wchar_t * OriginalCopy, DWORD Level );
void QueryKey(HKEY hKey, const wchar_t * proba, DWORD Level );
int counter = 0;
void __cdecl _tmain(void)
{
test( L"hardware\\description\\system", 0);
}
void test(wchar_t * OriginalCopy, DWORD Level)
{
HKEY hTestKey;
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, (LPCWSTR)OriginalCopy, 0, KEY_READ, &hTestKey ) == ERROR_SUCCESS )
{
//printf("\n%ls",OriginalCopy);
QueryKey(hTestKey, OriginalCopy, Level );
}
else printf("\nTest Failed");
RegCloseKey(hTestKey);
}
void QueryKey( HKEY hKey, const wchar_t * OriginalCopy, DWORD Level )
{
//printf("\n1. OriginalCopy: %ls Level %d", OriginalCopy, Level );
TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys=0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
DWORD i, retCode;
DWORD cchValue = MAX_VALUE_NAME;
// Get the class name and the value count.
retCode = RegQueryInfoKey(
hKey, // key handle
achClass, // buffer for class name
&cchClassName, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
// Enumerate the subkeys, until RegEnumKeyEx fails.
if (cSubKeys)
{
//printf( "\nNumber of subkeys: %d\n", cSubKeys);
for (i=0; i<cSubKeys; i++)
{
cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyExW(hKey,
i,
(LPWSTR)achKey,
&cbName,
NULL,
NULL,
NULL,
&ftLastWriteTime
);
if (retCode == ERROR_SUCCESS)
{
//_tprintf(TEXT("(%d) %s\n"), i+1, achKey);
//-------------------------------------------------------------------
HKEY subkey;
wchar_t NewCopy[MAX_PATH];
wcscpy( NewCopy, OriginalCopy );
wcscat( NewCopy, L"\\" );
wcscat( NewCopy, (const wchar_t *)achKey);
//printf("\nNew subkey found \"%ls\" Number of subkeys: %d\n",achKey, cSubKeys);
printf("\nNew OriginalCopy \"%ls\"Level: %d\n", NewCopy, Level);
if ( RegOpenKeyExW( HKEY_LOCAL_MACHINE, OriginalCopy, 0, KEY_READ, &subkey ) == ERROR_SUCCESS )
{
counter++;
test( NewCopy, Level+1 );
RegCloseKey( subkey );
}
else printf("\n-----Querykey Failed for %ls\n",OriginalCopy );
//-------------------------------------------------------------------
}
}
}
// Enumerate the key values.
/*if (cValues)
{
printf( "\nNumber of values: %d\n", cValues);
for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++)
{
cchValue = MAX_VALUE_NAME;
achValue[0] = '\0';
retCode = RegEnumValue( hKey,
i,
achValue,
&cchValue,
NULL,
NULL,
NULL,
NULL
);
if (retCode == ERROR_SUCCESS )
{
_tprintf(TEXT("(%d) %s\n"), i+1, achValue);
}
}
}*/
}
How to get registry Key name from an open Key Handle in Perl?
Browsing through the source, it doesn't look like Win32::Registry will let you take the handle and get back to the Key. I see three ways around this:
- Maintain a list of returned objects from
Open
and the path to them yourself. - Hack the module (subclass it, change the source) to do #1 for you.
- Or extend the Win32::Registry API to do what's shown in this stackoverflow answer: Determine path to registry key from HKEY handle in C++
Invoking RegCloseKey on a predefined registry key handle
The MSDN doc for the RegOpenKey
function infers that you would only want to call RegCloseKey
on a handle which you've programmatically created.
...If the key is not one of the predefined registry keys, call the RegCloseKey
function after you have finished using the handle.
Related Topics
Using Export Keyword with Templates
How to Make 'New[]' Default-Initialize the Array of Primitive Types
Qt/C++ - Accessing Mainwindow UI from a Different Class
Reason Why Not to Have a Delete MACro for C++
Is There a 128 Bit Integer in C++
C++ Inheritance and Function Overriding
How to Read and Write a Stl C++ String
Why Do Lambda Functions in C++11 Not Have Function<> Types
How to Get a Windows Symbol Server Set Up
Is It Legal to Declare a Constexpr Initializer_List Object
Overloaded Lambdas in C++ and Differences Between Clang and Gcc
Effective Way to Select Last Parameter of Variadic Template
Dark Transparent Layer Over a Qmainwindow in Qt
C++ Get All Bytes of a File in to a Char Array
Non-Defaulted Operator <=> Doesn't Generate == and != in C++20
How to Reduce the Size of Executable Produced by Mingw G++ Compiler