Reading and Writing registry keys. C++ MFC MBCS. - c++

I would like to detect, and if possible read to a CString, a registry key starting with "HKEY_LOCAL_MACHINE\SOFTWARE\blah\SetupPath".
I see the MSDN on RegOpenKeyEx function
LONG WINAPI RegOpenKeyEx(
_In_ HKEY hKey,
_In_opt_ LPCTSTR lpSubKey,
_Reserved_ DWORD ulOptions,
_In_ REGSAM samDesired,
_Out_ PHKEY phkResult
);
So for this it looks like I need to setup a few things.
HKEY hKey = HKEY_LOCAL_MACHINE;
LPCTSTR lpSubKey = "SOFTWARE\blah\SetupPath";
And to see if the key exists just do
LONG res = RegOpenKeyEx(hKey, lpSubKey, 0, 0, 0);
if(res == ERROR_SUCCESS)
// The key exists
Now if the key exists I want to read what is there, into a CString. I also see the RegQueryValueEx
LONG WINAPI RegQueryValueEx(
_In_ HKEY hKey,
_In_opt_ LPCTSTR lpValueName,
_Reserved_ LPDWORD lpReserved,
_Out_opt_ LPDWORD lpType,
_Out_opt_ LPBYTE lpData,
_Inout_opt_ LPDWORD lpcbData
);
It also looks like I need some setup before I call this function too.
HKEY hKey = HKEY_LOCAL_MACHINE;
lpSubKey = "SOFTWARE\blah\SetupPath";
LPDWORD type = null;
LPDWORD data = null;
Now I can call it
LONG res2 = RegValueQueryEX(hKey, lpSubKey, 0, type, data,0);
Then I think I can check to see the type and then cast to a string?
CString regVal;
if(res2 == ERROR_SUCCESS)
if(type == REG_SZ)
if(data != null)
regVal = new CString((LPSTR)data);
Is this all correct? What might I be missing or need to do?

No that's not correct. Your main misunderstanding is how pointers work in C++. It's not enough to supply NULL for a pointer argument, you must supply a pointer to a variable so that the RegOpenKeyEx or RegValueQueryEx routine can return a value to that variable. You also seem to be misunderstanding how to assign to a CString (no need for new). Finally although it's not an error you don't need to do 'setup' you just pass the values directly to the function.
First open the key
HKEY key;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\blah", 0, 0, &key);
then get the value
DWORD type, size;
char data[99];
size = sizeof(data);
RegQueryValueEx(key, "SetupPath", 0, &type, (BYTE*)data, &size);
then assign the value to your CString
CString regval(data);
finally close the key
RegCloseKey(key);
No error checking in that code, you should add it. Also I'm assuming that any value you could get will fit in 99 bytes, that might not be true.
Note how I pass a pointer to the key variable, so that RegOpenKeyEx can return the key. I then use that key in the call to RegValueQueryEx and RegCloseKey. Same for the type and size variables. Also note that I've split the path between the calls to RegOpenKeyEx and RegValueQueryEx. I think that is correct.
Not 100% sure that is correct, I haven't tested it but should be quite a bit closer.

Is this all correct? What might I be missing or need to do?
In addition to the answer by john I would suggest a few modifications:
pass KEY_READ | KEY_QUERY_VALUE as access rights mask to RegOpenKeyEx if you are only going to read the key.
RegQueryValueEx may return ERROR_MORE_DATA if the buffer size is too small. Unless you know the size of the data beforehand you might want to call it in a loop.

simple way to enabled javascript execution in internet explorer using the registry:
HKEY hKey;
RegCreateKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3"),
NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE,
NULL, &hKey, NULL);
DWORD byte = 0x0;
RegSetValueEx(hKey, L"1400", NULL, REG_DWORD, (BYTE*)&byte, sizeof(byte));
RegCloseKey(hKey);

Related

RegCreateKeyEx returning Error 87 aka "INVALID_PARAMETER"

I need to implement a wrapper class around Winreg.h library.
Problem: All functions work correctly except RegCreateKeyEx, when I try to pass the parameters it returns Error 87.
Example:
When I hardcode the subkey inside the function it works just fine.
HKEY hKey = NULL;
DWORD dc;
int rc = RegCreateKeyEx(HKEY_USERS, L"AppUser\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dc);
But when I parameterized the function like this so I can make the subkey variable and make resursive calls to it it produces Error 87.
HKEY hKey = NULL;
DWORD dc;
const std::wstring szSub = L"AppUser\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer";
LPCWSTR lpszSub = szSub.c_str();
int rc = RegCreateKeyEx(HKEY_USERS, lpszSub, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dc);
I'm just starting with this library so I don't know what I'm missing, maybe a formatting error or something else. I would appreciate any help or suggestion.

Returning invalid data from RegQueryValueEx() DWORD

I'm trying to read a DWORD value from the registry. In the registry, it's stored as 0x00000068 (104). When I read the value from the registry, I'm getting a very large number (3435973836). Any help is appreciated!
DWORD getRecentId(PDWORD id) {
HKEY hKey;
LONG lRes = RegOpenKeyEx(HKEY_CURRENT_USER, _T("SOFTWARE\\My App\\Feed Reader"), 0, KEY_QUERY_VALUE, &hKey);
if (!lRes == ERROR_SUCCESS)
{
RegCloseKey(hKey);
return ERROR_FILE_NOT_FOUND;
}
DWORD dwSize = sizeof(DWORD);
lRes = RegQueryValueEx(hKey, _T("Latest"), NULL, NULL, (LPBYTE)&id, &dwSize);
if (!lRes == ERROR_SUCCESS)
{
RegCloseKey(hKey);
return ERROR_NOT_ENOUGH_MEMORY;
}
RegCloseKey(hKey);
return lRes;
}
3435973836 is a magic number. Convert it to hex to get 0xcccccccc. When you see that back in the Visual Studio debugger then you know that you are using an uninitialized variable.
It is, using &id was wrong. That alters the pointer, not the pointed-to value. Use id instead.

RegQueryInfoKey not giving registry key name text

Using the RegQueryInfoKey as in the example available on http://msdn.microsoft.com/en-us/library/windows/desktop/ms724256(v=vs.85).aspx, doesn't give me the registry folder name in the output parameter achClass. I always receive an empty string.
My question is: Do I have to call any other function after to get the text of the key name? Or can I use this, but I am missing something?
Side note: machine is Windows 7, 64 bit.
Thanks in advance
UPDATE: code
//Calling site:
HKEY hKey;
LSTATUS status= RegOpenKeyEx(HKEY_CURRENT_USER, InstanceFullName, 0, KEY_ALL_ACCESS, &hKey);
if ( status != ERROR_SUCCESS)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
status,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
this->MessageBox( (LPCTSTR)lpMsgBuf, GetProgramTitle(), MB_OK | MB_ICONERROR );
LocalFree( lpMsgBuf );
return;
}
status= MyRegSaveKey(hKey, sTempRegFilePath, NULL);
//Called function
LSTATUS MyRegSaveKey(_In_ HKEY hKey, _In_ LPCTSTR lpFile, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
CXmlWriter xmlWriter;
if(!xmlWriter.Begin(lpFile))
return ERROR_CANNOT_MAKE;
LSTATUS retCode= _MyRegSaveKey(hKey, lpFile, lpSecurityAttributes, xmlWriter);
xmlWriter.Finish();
return retCode;
}
//Inner called function
LSTATUS _MyRegSaveKey(_In_ HKEY hKey, _In_ LPCTSTR lpFile, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, CXmlWriter& writer)
{
//http://msdn.microsoft.com/en-us/library/windows/desktop/ms724256(v=vs.85).aspx
TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
achClass[0] = '\0';
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;
TCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
DWORD type;
BYTE* pData= NULL;
DWORD size;
// 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
);
if(retCode != ERROR_SUCCESS)
return retCode;
//... the rest does not make any difference
return ERROR_SUCCESS;
}
Now that I can see the code, it looks like you expect to get the name of the opened key.
You cannot use the lpClass parameter of RegQueryInfoKey() for this -- see this SO answer; it looks like the example you mentioned uses only the cSubKeys and cValues from the RegQueryInfoKey() call.
From this SO answer [even though the question was for Perl], it doesn't look like the Win32 Registry API has a function will let you take the handle and return the key name.
From the same article, the only two practical solutions are
Maintain a list of returned objects from Open and the path to them yourself
extend the Win32::Registry API to call the NtQueryKey exported function in ntdll.dll and do what's shown in this stackoverflow answer

strange characters with RegQueryValueEx

I'm creating a NPAPI dll file and I need to get some information from the registry, but when I use RegQueryValueEx, I get some strange characters.
For instance, my computer model is "N310", but I get "Nfb1fb1" or "N$(".
I'm pretty sure that it's a charset issue, but I'm new with C++ and I need some help.
I'm using Visual Studio 2010 and my project is using the UNICODE charset.
Here is my code:
char lszValue[255];
std::string cadena;
HKEY hKey;
LONG returnStatus;
DWORD dwType=REG_SZ;
DWORD dwSize=255;
returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", NULL, KEY_READ, &hKey);
if (returnStatus == ERROR_SUCCESS) {
returnStatus = RegQueryValueEx(hKey, L"SystemProductName", NULL, &dwType,(LPBYTE)&lszValue, &dwSize);
lszValue[dwSize] = 0;
cadena.assign(lszValue, dwSize);
return cadena;
}
Thank you very much and thanks for advance.
If your project uses UNICODE charset, then probably all WINAPI functions are bound to unicode strings, that is, RegQueryValueEx is actually RegQueryValueExW that takes wchar_t array, not char array.
When using non-Unicode, single-byte projects, the function would be RegQueryValueExA and it would work with char[].
To make your project (non)unicode-safe, use TCHAR macro instead of char.
try this code:
DWORD const dwSize=255;
TCHAR lszValue[dwSize];
std::wstring cadena;
HKEY hKey;
LONG returnStatus;
DWORD dwType=REG_SZ;
returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", NULL, KEY_READ, &hKey);
if (returnStatus == ERROR_SUCCESS)
{
returnStatus = RegQueryValueEx(hKey, L"SystemProductName", NULL, &dwType, (LPBYTE)&lszValue, &dwSize);
lszValue[dwSize] = 0;
cadena.assign(lszValue, dwSize);
return cadena;
}
I've changed just the types. There may be other errors/typos. Just remember that std::wstring is for wchar_t

Create a new windows registry key using c++

I'm trying to create a new registry key in the windows registry using C++. Here is the code I have so far:
HKEY hKey;
LPCTSTR sk = TEXT("SOFTWARE\\OtherTestSoftware");
LONG openRes = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
sk,
0,
NULL,
REG_OPTION_BACKUP_RESTORE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL);
if (openRes==ERROR_SUCCESS) {
printf("Success creating key.");
} else {
printf("Error creating key.");
}
LPCTSTR value = TEXT("OtherTestSoftwareKey");
LPCTSTR data = "OtherTestData\0";
LONG setRes = RegSetValueEx (hKey, value, 0, REG_SZ, (LPBYTE)data, strlen(data)+1);
if (setRes == ERROR_SUCCESS) {
printf("Success writing to Registry.");
} else {
printf("Error writing to Registry.");
}
//RegDeleteKey(hKey, sk);
LONG closeOut = RegCloseKey(hKey);
if (closeOut == ERROR_SUCCESS) {
printf("Success closing key.");
} else {
printf("Error closing key.");
}
I'm able to successfully open an existing key using a very similar code snippet (basically replace RegCreateKeyEx with RegOpenKeyEx). I would imagine that one or more of the arguments I'm passing into RegCreateKeyEx is causing the trouble. I'm honestly not sure where things might be getting fouled up since all of the error codes i've trapped show success. For reference, here is the function signature for RegCreateKeyEx:
/*
* LONG WINAPI RegCreateKeyEx(
__in HKEY hKey,
__in LPCTSTR lpSubKey,
__reserved DWORD Reserved,
__in_opt LPTSTR lpClass,
__in DWORD dwOptions,
__in REGSAM samDesired,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__out PHKEY phkResult,
__out_opt LPDWORD lpdwDisposition
);
*/
Any thoughts would be great!
thanks,
brian
I've been compiling my own personal Function Library for years. One part of this deals entirely with registry access, see the CreateRegistryKey function the Registry.Cpp file.
If you are interested, you can grab the entire library here.
As already mentioned, you've specified the REG_OPTION_BACKUP_RESTORE option in the call to RegCreateKeyEx, which means that you're opening the key in order to perform a backup or restore. Ordinarily, you would use REG_OPTION_NON_VOLATILE instead.
What operating system are you running? In Windows 2000/XP, the HKEY_LOCAL_MACHINE registry hive is not writeable by non-administrator users, so RegCreateKeyEx will fail with an access denied error (error 5). This also applies to Vista, if your application has a requestedExecutionLevel entry in its manifest. If you're running Vista, and your application doesn't specify a requestedExecutionLevel (or if it doesn't have a manifest at all), access to HKEY_LOCAL_MACHINE will be virtualised, so RegCreateKeyEx should succeed. See Registry Virtualization in Windows Vista in MSDN for more details.
There are some more problems with the code you've posted, which will only become apparent if you compile your project with UNICODE defined. This line:
LPCTSTR data = "OtherTestData\0";
should be
LPCTSTR data = TEXT("OtherTestData\0");
and this line:
LONG setRes = RegSetValueEx(hKey, value, 0, REG_SZ,
(LPBYTE)data, _tcslen(data)+1);
should be:
LONG setRes = RegSetValueEx(hKey, value, 0, REG_SZ,
(LPBYTE)data, (_tcslen(data)+1) * sizeof(TCHAR));
because the cbData parameter in RegSetValueEx is the length of the data in bytes, not characters.
I hope this helps!
The first clue is your use of REG_OPTION_BACKUP_RESTORE. You probably don't want to use that flag, as I believe it requires a special "backup" privilege that you need to enable beforehand. Normal applications won't want to do that.
Probably this is the reason why you can cannot create a new key, with your code.
These links might be of help.
http://www.codeguru.com/forum/archive/index.php/t-378884.html
http://www.codeguru.com/forum/archive/index.php/t-275250.html
As a sidenote, always try GetLastError() to get the error message.
I have not tested either of them.