Unable to read certain registry keys in C - c

I'm using RegOpenKeyEx() and RegQueryValueEx() to try and get the value for six keys in the Windows registry. I'm able to do it for four of the six but am failing on certain others.
wchar_t * getRegKeyValue(HKEY rootKeyToGet, LPCWSTR subKeyToGet, LPCWSTR valueToGet)
{
HKEY resultHKey = 0;
wchar_t resultString[255] = L"";
DWORD dwType = REG_SZ;
DWORD resultSize = 255;
// See if the subkey exists. If it does, get its value.
if (RegOpenKeyEx(rootKeyToGet, subKeyToGet, NULL, KEY_ALL_ACCESS, &resultHKey) == ERROR_SUCCESS)
{
RegQueryValueEx(resultHKey, valueToGet, NULL, &dwType, (LPBYTE) &resultString, &resultSize);
}
RegCloseKey(resultHKey);
resultHKey = NULL;
RegCloseKey(rootKeyToGet);
rootKeyToGet = NULL;
return resultString;
}
The following are some successful calls:
swprintf(buffer, L"&ie=%s", getRegKeyValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Internet Explorer", L"Version"));
swprintf(buffer, L"&os=%s.", getRegKeyValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentVersion"));
wcscat(url, getRegKeyValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CurrentBuild"));
Example of an unsuccessful call:
wcscpy(buffer, getRegKeyValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"CSDVersion"));
I'm able to open the key in the unsuccessful call but the query for that value returns an empty string. I'm running Visual Studio as an administrator. Have been scratching my head for the last day on where I am going wrong.
Update: The code returned is ERROR_FILE_NOT_FOUND. The codes are most definitely shown to exist in regedit.

I guess that you have a 32 bit process and a 64 bit machine. When this happens, registry redirection confounds matters. Attempts to read HKLM\Software\... get redirected to HKLM\Software\Wow64Node\.... So you need to open the 64 bit view of the registry with the RegistryView enumeration.

Related

GetNamedSecurityInfo fails for registry key where GetSecurityInfo succeeds

I have a registry key ACL reading request like this:
PACL dacl = NULL;
PSECURITY_DESCRIPTOR secDesc = NULL;
if (GetNamedSecurityInfoW(L"HKEY_CURRENT_USER\\SOFTWARE\\SomeSoftware\\SomeKey", SE_REGISTRY_KEY, DACL_SECURITY_INFORMATION, NULL, NULL, &dacl, NULL, &secDesc) != ERROR_SUCCESS)
{ /*... */ }
And it fails with error 87, invalid parameter. However, if I use
HKEY handle;
DWORD Ret = RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\SomeSoftware\\SomeKey", 0, KEY_ALL_ACCESS, &handle);
if (Ret != ERROR_SUCCESS) { /* ... */ }
DWORD secDescSize = 4096;
secDesc = LocalAlloc(LMEM_FIXED, secDescSize);
Ret = (DWORD)RegGetKeySecurity(handle, DACL_SECURITY_INFORMATION, secDesc, &secDescSize);
if (Ret != ERROR_SUCCESS) { /* ... */ }
RegOpenKey() and RegGetKeySecurity() succeed, and running GetSecurityDescriptorDacl() on the result of RegGetKeySecurity() also works.
This code works fine for SE_FILE_OBJECT and reading a directory's ACL.
This code is inside a 32-bit DLL in a 32-bit app in Windows 10 Pro 64-bit. I'm targeting XP and above, using Visual Studio 2019 Preview.
Anything I could have missed in parameter validation?
L"HKEY_CURRENT_USER\\SOFTWARE\\SomeSoftware\\SomeKey" is not a valid object name for GetNamedSecurityInfoW(). Read the SE_OBJECT_TYPE documentation for the proper format to use for a registry key:
SE_REGISTRY_KEY
Indicates a registry key. A registry key object can be in the local registry, such as CLASSES_ROOT\SomePath or in a remote registry, such as \\ComputerName\CLASSES_ROOT\SomePath.
The names of registry keys must use the following literal strings to identify the predefined registry keys: "CLASSES_ROOT", "CURRENT_USER", "MACHINE", and "USERS".
Try L"CURRENT_USER\\SOFTWARE\\SomeSoftware\\SomeKey" instead.

Read "OS install date" value from registry with RegQueryValueExA() api failed

I wanna read Windows Install Date value from registry using Windows API as bellow :
HKEY hKey = { 0 };
LONG lResult = ERROR_SUCCESS;
// Open a registry key
lResult = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
0, KEY_READ, &hKey);
// If registry key opened
if (lResult == ERROR_SUCCESS)
{
// Get OS install date/time
DWORD dwInstallDate = 0;
dwBufferSize = sizeof(DWORD);
if (RegQueryValueExA(hKey, "InstallDate", 0, NULL, (LPBYTE)&dwInstallDate, &dwBufferSize) == ERROR_SUCCESS)
{
printf("OS Install Date is : %lu", dwInstallDate);
}
else
{
printf("The specific key not found!");
}
// Finally we should close the key when we finished with it
RegCloseKey(hKey);
}
But the output is always 0, while "InstallDate" value is 1520291827:
OS Installe Date is : 0
Also, I'm used of "%ld" and "d" formats, but it has the same output...
The "InstallDate" value in registry, contained a REG_DWORD type.
By the way, when i create a new REG_DWORD value, my code cannot read it :
For example , I create a value in bellow reg-address as "test" with 123 data :
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
But dwInstallDate will be 0 instead of 123 :
RegQueryValueExA(hKey, "test", 0,
NULL, (LPBYTE)&dwInstallDate,
&dwBufferSize);
Any Suggestion? I'm confused about this action...
According Microsoft :
KEY_WOW64_32KEY (0x0200) :
Indicates that an application on 64-bit Windows should operate on the 32-bit registry view. This flag is ignored by 32-bit Windows. For more information, see Accessing an Alternate Registry View.
This flag must be combined using the OR operator with the other flags in this table that either query or access registry values.
Windows 2000: This flag is not supported.
KEY_WOW64_64KEY (0x0100) :
Indicates that an application on 64-bit Windows should operate on the 64-bit registry view. This flag is ignored by 32-bit Windows. For more information, see Accessing an Alternate Registry View.
This flag must be combined using the OR operator with the other flags in this table that either query or access registry values.
Windows 2000: This flag is not supported.
I used of KEY_WOW64_64KEY | KEY_READ either way x86 and x64 :
// Open a registry key
lResult = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
0, KEY_WOW64_64KEY | KEY_READ, &hKey);
It does work.

Opening registry key in c

I have create a key using regedit, now I want to get its value. It doesn't give any error but it isn't showing anything.
Code :
int main() {
HKEY hKey;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Ehsan Akbari", 0, KEY_ALL_ACCESS, &hKey);
TCHAR sz[50];
DWORD size = 50,type;
RegEnumValue(hKey, 0, L"test", &size, NULL, &type, (LPBYTE)sz, &size);
RegCloseKey(hKey);
getch();
return 0;
}
An image of regedit :picture
What am I doing wrong?
Edit
When I debugged I saw that hKey is NULL, but GetLastError doesn't report anything.
Here are the immediate problems that I can see:
You detect no errors because you don't check for errors. Read the documentation for each function. The error code is returned in the return value.
You ask for KEY_ALL_ACCESS which won't be granted under HKLM. You need to request just read access KEY_READ.
Your screenshot shows the key has been created under HKCU, and you're trying to open it under HKLM.
RegEnumValue expects the size of the data buffer in bytes. You pass the length, the number of characters.
You are mixing Unicode literals and TCHAR. This is pointless. Your code won't compile targeting MBCS and in any case you don't care about Win98 any more. Stop using TCHAR and use wchar_t instead.
The lpValueName parameter must be a modifiable buffer. You pass a literal. Remember that this function enumerates values. It does not read specific named values as perhaps you expect.
The lpcchValueName parameter contains the size of the buffer you passed to lpcchValue in characters. You pass the length of the data buffer.
The data returned may not be null terminated. You must protect against this as described in the documentation.
For a C program which ignores its arguments, the correct main is int main(void).
I expect there are more errors but I stopped looking at this point. I recommend you spend some quality time with the documentation.
To open the path "Ehsan Akbari" in HKEY_CURRENT_USER you could try this:
HKEY hKey;
long result = RegOpenKeyEx(HKEY_CURRENT_USER , TEXT("\\Ehsan Akbari"), 0, KEY_ALL_ACCESS, &hKey);
if ( result == ERROR_SUCCESS )
{
cout << "OK" << endl;
}
else
{
cout << "Error " << result << endl;
}

RegQueryValue fails but RegQueryValueEx returns a value

I am attempting to play with some of the 16 and 32 bit registry functions, and I'm having trouble with using RegQueryValue (not extended). I am opening a handle to HKLM\Software\Microsoft\EventSystem (this key was chosen at random, the problem is persistent across keys). When I call RegQueryValue for "Configured", there is an error. However, for RegQueryValueEx, I am actually able to get the value.
I am running this on Windows 7 x64, tested with admin rights (Not having admin rights means RegOpenKeyEx fails with insufficient rights).
Here is the code (see https://stackoverflow.com/questions/455434/how-should-i-use-formatmessage-properly-in-c for printErrorMessage):
#define BUFLEN 80
int main() {
HKEY hkey;
DWORD ret = RegOpenKeyA(rootKey, "Software\\Microsoft\\EventSystem", &hkey);
printf("Opened key, handle is %i\n", hkey);
LONG buflen = BUFLEN;
DWORD dwbuflen = BUFLEN;
char data[BUFLEN];
BYTE bdata[BUFLEN];
ret = RegQueryValueA(hkey, "Configured", data, &buflen);
if (ret != ERROR_SUCCESS) {
printf("Unable to open Configured with RegQueryValueA\n");
printErrorMessage(ret);
} else {
printf("Value of Configured was %s\n", data);
}
ret = RegQueryValueExA(hkey, "Configured", 0, NULL, bdata, &dwbuflen);
if (ret != ERROR_SUCCESS) {
printf("Unable to open Configured with RegQueryValueExA\n");
printErrorMessage(ret);
} else {
printf("Value of Configured was %s\n", bdata);
}
}
And here is the output:
Opened key, handle is 68
Unable to open Configured with RegQueryValueA
The system cannot find the file specified.
Value of Configured was ☺
(Configured's value is wonky because I am not yet bothering to convert from REG_DWORD to a string, but it is immaterial to the problem I am having).
When you call RegQueryValue(hkey, "Configured"), that tries to read the default value (or unnamed value) of the key named "Configured". This is the semantics of RegQueryValue() as described by MSDN.
So RegQueryValue() cannot be used to read named values like "Configured", so you must use RegQueryValueEx() if you want to read a named value.
You're querying a value, but the string parameter for RegQueryValue() is a subkey. See msdn for RegQueryValue() vs. RegQueryValueEx().

SetupDiGetDeviceRegistryProperty: "The data area passed to a system call is too small" error

I have a code that enumerates USB devices on Windows XP using SetupAPI:
HDEVINFO hDevInfo = SetupDiGetClassDevs( &_DEVINTERFACE_USB_DEVICE, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
for (DWORD i = 0; ; ++i)
{
SP_DEVINFO_DATA devInfo;
devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
BOOL succ = SetupDiEnumDeviceInfo(hDevInfo, i, &devInfo);
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
if (!succ) continue;
DWORD devClassPropRequiredSize = 0;
succ = SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfo, SPDRP_COMPATIBLEIDS, NULL, NULL, 0, &devClassPropRequiredSize);
if (!succ)
{
// This shouldn't happen!
continue;
}
}
It used to work for years, but now I get FALSE from SetupDiGetDeviceRegistryProperty, last error is "The data area passed to a system call is too small".
It seems that my call parameters correspond to the documentation for this function: http://msdn.microsoft.com/en-us/library/windows/hardware/ff551967(v=vs.85).aspx
Any ideas what's wrong?
Problem was in your original code: SetupDiGetDeviceRegistryProperty function may return FALSE (and set last error to ERROR_INSUFFICIENT_BUFFER) when required property doesn't exist (or when its data is not valid, yes they have been lazy to pick a proper error code) so you should always check for ERROR_INSUFFICIENT_BUFFER as a (not so) special case:
DWORD devClassPropRequiredSize = 0;
succ = SetupDiGetDeviceRegistryProperty(
hDevInfo,
&devInfo,
SPDRP_COMPATIBLEIDS,
NULL,
NULL,
0,
&devClassPropRequiredSize);
if (!succ) {
if (ERROR_INSUFFICIENT_BUFFER == GetLastError() {
// I may ignore this property or I may simply
// go on, required size has been set in devClassPropRequiredSize
// so next call should work as expected (or fail in a managed way).
} else {
continue; // Cannot read property size
}
}
Usually you may simply ignore this error when you're reading property size (if devClassPropRequiredSize is still zero you can default it to proper constant for maximum allowed length). If property can't be read then next call SetupDiGetDeviceRegistryProperty will fail (and you'll manage error there) but often you're able to read value and your code will work smoothly.

Resources