Enumerate Windows Registry (WinAPI) - Delphi

DarkCoderSc
Jean-Pierre LESUEUR
// ...
uses
System.SysUtils, Winapi.Windows, Generics.Collections;
// ...
const RRF_RT_ANY = $0000FFFF;
// ...
function RegGetValueW(
hkey : HKEY;
lpSubKey : LPCWSTR;
lpValue : LPCWSTR;
dwFlags : DWORD;
var dwType : DWORD;
pvData : PVOID;
var pcbData : DWORD
) : LONG; stdcall; external advapi32 name 'RegGetValueW';
// ...
procedure EnumerateRegistryKeys(const ARegistryHive : HKEY; const ARegistryPath: String; var _outKeys : TList<String>; var _outValues : TDictionary<String, String>);
begin
var hOpenedKey : HKEY;
var ACloseKey := False;
if not Assigned(_outKeys) then
_outKeys := TList<String>.Create()
else
_outKeys.Clear();
if not Assigned(_outValues) then
_outValues := TDictionary<String, String>.Create()
else
_outValues.Clear();
if not String.IsNullOrWhiteSpace(ARegistryPath) then begin
var ARet := RegOpenKeyEx(
ARegistryHive,
PWideChar(ARegistryPath),
0,
KEY_READ,
hOpenedKey
);
if ARet <> ERROR_SUCCESS then
raise EWindowsException.Create('RegOpenKeyEx');
ACloseKey := True;
end else
hOpenedKey := ARegistryHive;
try
var ASubKeysCount : DWORD;
var AMaxKeyNameLength : DWORD;
var AValuesCount : DWORD;
var AMaxValueNameLength : DWORD;
var ARet := RegQueryInfoKeyW(
hOpenedKey,
nil,
nil,
nil,
@ASubKeysCount,
@AMaxKeyNameLength,
nil,
@AValuesCount,
@AMaxValueNameLength,
nil,
nil,
nil
);
if ARet <> ERROR_SUCCESS then
raise EWindowsException.Create('RegQueryInfoKeyW');
if (ASubKeysCount = 0) and (AValuesCount = 0) then
raise Exception.Create('No keys or values');
// Include terminating NULL characters
Inc(AMaxKeyNameLength);
Inc(AMaxValueNameLength);
var ABufferSize := 0;
if AMaxKeyNameLength > AMaxValueNameLength then
ABufferSize := AMaxKeyNameLength * SizeOf(WideChar)
else
ABufferSize := AMaxValueNameLength * SizeOf(WideChar);
var pNameBuffer : PWideChar := nil;
GetMem(pNameBuffer, ABufferSize);
try
// Enumerate SubKeys
if ASubKeysCount > 0 then begin
for var I := 0 to ASubKeysCount -1 do begin
ZeroMemory(pNameBuffer, AMaxKeyNameLength * SizeOf(WideChar));
var AKeyLength := AMaxKeyNameLength;
ARet := RegEnumKeyExW(
hOpenedKey,
I,
pNameBuffer,
AKeyLength,
nil,
nil,
nil,
nil
);
if ARet <> ERROR_SUCCESS then
continue;
///
_outKeys.Add(String(pNameBuffer));
end;
end;
// Enumerate Key-Values
if AValuesCount > 0 then begin
for var I := 0 to AValuesCount -1 do begin
ZeroMemory(pNameBuffer, AMaxKeyNameLength * SizeOf(WideChar));
var AValueNameLength := AMaxValueNameLength;
ARet := RegEnumValueW(
hOpenedKey,
I,
pNameBuffer,
AValueNameLength,
nil,
nil,
nil,
nil
);
if ARet <> ERROR_SUCCESS then
continue;
///
var AValueName := String(pNameBuffer);
var AValueType : DWORD;
var AValueDataSize : DWORD;
var AData : String;
ARet := RegGetValueW(
hOpenedKey,
nil,
PWideChar(AValueName),
RRF_RT_ANY,
AValueType,
nil,
AValueDataSize
);
if ARet = ERROR_SUCCESS then begin
var pData : Pointer;
GetMem(pData, AValueDataSize * SizeOf(WideChar));
try
RegGetValueW(
hOpenedKey,
nil,
PWideChar(AValueName),
RRF_RT_ANY,
AValueType,
pData,
AValueDataSize
);
case AValueType of
REG_SZ : begin
AData := String(PWideChar(pData));
end;
REG_DWORD : AData := IntToStr(PDWORD(pData)^);
REG_QWORD : AData := IntToStr(PUInt64(pData)^);
// Etc...
// ... handle other value types ... //
// https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types?WT_mc_id=SEC-MVP-5005282
end;
///
_outValues.Add(AValueName, AData);
finally
FreeMem(pData, AValueDataSize);
end;
end else
AData := '<could not read>';
end;
end;
finally
FreeMem(pNameBuffer, ABufferSize);
end;
finally
if ACloseKey then
RegCloseKey(hOpenedKey);
end;
end;
procedure PrintKeysValues(const AKeys : TList<String>; const AValues : TDictionary<String, String>);
begin
if Assigned(AKeys) and (AKeys.Count > 0) then begin
WriteLn('Keys');
for var AKey in AKeys do
WriteLn(#9 + AKey);
end;
if Assigned(AValues) and (AValues.Count > 0) then begin
WriteLn('Values');
var AValue : String;
for var AValueName in AValues.Keys do begin
if not AValues.TryGetValue(AValueName, AValue) then
Exit();
WriteLn(Format(#9 + '%s:%s', [AValueName, AValue]));
end;
end;
end;
// ...
var AKeys := TList<String>.Create();
var AValues := TDictionary<String, String>.Create();
try
// Example 1 : HKCU Root
try
EnumerateRegistryKeys(HKEY_CURRENT_USER, '', AKeys, AValues);
WriteLn('Example Enumerate HKCU Root:');
PrintKeysValues(AKeys, AValues);
except
// ...
end;
WriteLn;
WriteLn(' --- ');
WriteLn;
// Example 2 : HKCU\Software\Valve\Steam
try
EnumerateRegistryKeys(HKEY_CURRENT_USER, 'Software\RegisteredApplications', AKeys, AValues);
WriteLn('Example Enumerate Steam Key:');
PrintKeysValues(AKeys, AValues);
except
// ...
end;
finally
FreeAndNil(AKeys);
FreeAndNil(AValues);
end;
// ...
Implemented By Technique
Created
April 13, 2025
Last Revised
April 13, 2025