strange characters with RegQueryValueEx - c++

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

Related

lpData not get value after RegQueryValueEx

I'm not sure where problem is occur.
I have demo code get value from an registry:
using namespace std;
typedef struct REGKEYS
{
HKEY hKey;
LPCTSTR subKey;
LPCTSTR value;
LPCTSTR name;
LPCTSTR file;
LPCTSTR tag;
} REGKEYS;
REGKEYS regkeys = {HKEY_LOCAL_MACHINE,"Software\\Internet Download Manager", "Serial", "IDM", NULL, NULL};
HKEY hKey;
LPBYTE szDataBuf;
DWORD dwSize;
int _tmain(int argc, _TCHAR* argv[])
{
RegOpenKeyEx(regkeys.hKey, regkeys.subKey, 0, KEY_READ, &hKey);
RegQueryValueEx(hKey, regkeys.value, NULL, NULL, szDataBuf, &dwSize);
int lerr = GetLastError();
system("pause");
return 0;
}
When debug, I see regkeys.hKey not point to anything (it need point to "HKEY_LOCAL_MACHINE", is it?).
And szDataBuf is empty.
(GetLastError() not help me - it return 0)
Anyone tell me where is problem and how to fix it?
EDIT2:
I edited my code to :
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwSize = 0;
RegOpenKeyEx(regkeys.hKey, regkeys.subKey, 0, KEY_READ, &hKey);
RegQueryValueEx(hKey, regkeys.value, NULL, NULL, NULL, &dwSize);
char *szDataBuf = new char(dwSize);
RegQueryValueEx(hKey, regkeys.value, NULL, NULL, (LPBYTE)szDataBuf, &dwSize);
delete[] szDataBuf;
system("pause");
return 0;
}
I debug and see szDataBuf get right value, but my program break and get warning: warning C4244: 'initializing' : conversion from 'DWORD' to 'char', possible loss of data.
First of all, your error checking code is not correct. The registry functions all return Win32 error codes. You need to take notice of them and check for errors.
To be clear, GetLastError is no use because these functions do not call SetLastError. They return the error code directly. You must read the documentation carefully. There are often subtle differences in the way different parts of Win32 do error handling.
The code in your updated question is better, but it still fails to check for errors in the call to RegOpenKeyEx.
Now, beyond that you are not actually calling RegQueryValueEx correctly. You have not initialized dwSize, and you have not allocated szDataBuf. Since these are global variables, they will be zero initialised. So your call to RegQueryValueEx will indeed succeed if the value exists. But you cannot expect any value to arrive in the buffer since you did not allocate a buffer. You are passing NULL to the lpData parameter.
So, allocate a buffer. For instance:
char szDataBuf[128];
Initialise dwSize:
DWORD dwSize = sizeof(szDataBuf);
Then your call to RegQueryValueEx should be
int lerr = RegQueryValueEx(hKey, regkeys.value, NULL, NULL,
(LPBYTE)szDataBuf, &dwSize);
Although you may wish to allocate the buffer dynamically:
dwSize = 0;
int lerr = RegQueryValueEx(hKey, regkeys.value, NULL, NULL, NULL, &dwSize);
// check lerr here
vector<char> szDataBuf(dwSize);
int lerr = RegQueryValueEx(hKey, regkeys.value, NULL, NULL,
(LPBYTE)&szDataBuf[0], &dwSize);
// check lerr here
You might also consider avoiding the use of global variables here. All of the variables you use would be make more sense as locals.

c++ RegCreateKeyEx LPCWSTR from std::string

I'm writting few operations in registry and I got stuck for two days at this. Really don't know how to solve that. So, its my code:
HKEY hkey;
DWORD dwDisposition;
string address = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
QString qAddr= ui->networkCard->itemData(ui->networkCard->currentIndex()).toString();
address += qAddr.toStdString();
string sAddr = qAddr.toStdString();
cout << address; // here is the value I want to proceed as 2nd arg in RegCreateKeyEx
size_t size = address.size();
wchar_t szBuff[size];
swprintf(szBuff, size, L"%s", address.c_str());
cout << szBuff << endl; // but after conversion I get some hex data like 0x28d172 :(
if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, szBuff, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &dwDisposition) == ERROR_SUCCESS){
DWORD dwType, dwSize;
dwType = REG_DWORD;
....
RegCreateKeyEx requires a LPCWSTR arg, but I really don't know how to do it from a std::string. Can u help me fixing this? :)
Thank you!
RegCreateKeyEx requires LPCWSTR only if your project is set to unicode. If you want a unicode project then use std::wstring instead of std::string. If you don't want a unicode project then change the project Character Set setting to Multi-Byte Character Set, which will let you use std::string.

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

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);

How to convert LPWSTR* (or WCHAR*) to LPWSTR

I'm having a difficulty in converting a value to LPWSTR. I'm getting a registry value, and trying to return the result as LPWSTR. It appears the registry call using RegQueryValueExW works with a variety of types going in to store the result, but I can't cast any of them back to LPWSTR.
LPWSTR value;
HKEY hKey;
long result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"RegEntry1", 0, ACCESS|KEY_WOW64_32KEY, &hKey);
if (result == ERROR_SUCCESS)
{
//WCHAR buffer[512];
//TCHAR buffer[512];
LPWSTR buffer[512];
DWORD bufferSize = sizeof(buffer);
ULONG queryVal = 0;
queryVal = RegQueryValueExW(hKey, L"Path", 0, NULL, (LPBYTE)buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
//Access violation error here; I need some type of conversion.
value = buffer;
}
}
No posts that I've read on here so far have led me to an answer. C++ is not my primary dev language.
UPDATE: None of the proposed answers worked for me. I found an alternative way to do what I needed.
You don't want a buffer of LPWSTR, you want a buffer of wchar_t. A pointer to that will be LPWSTR as it's a typedef for wchar_t *.
These two lines from WinNT.h are relevant:
typedef wchar_t WCHAR; // wc, 16-bit UNICODE character
typedef __nullterminated WCHAR *NWPSTR, *LPWSTR, *PWSTR;
Edit: I suspect the problem is with the part of the code you haven't shown us. Are you returning value from a function? If so then the problem is that you're returning a pointer to a buffer that has gone out of scope and been destroyed. I would return a std::wstring or CString instead.
Your buffer variable is declaring an array of 512 wchar_t* pointers when it should be declaring an array of 512 wchar_t characters instead. The first commented-out line of code is the correct code to use:
WCHAR buffer[512];
DWORD bufferSize = sizeof(buffer);
ULONG queryVal = RegQueryValueExW(hKey, L"Path", 0, NULL, (LPBYTE)buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
//...
}
Keep in mind that the buffer will not be null-terminated if the Registry value was not stored with its own null-terminator, so you should allocate some extra space for your own null terminator, just in case:
WCHAR buffer[512+1];
DWORD bufferSize = (sizeof(buffer) - sizeof(WCHAR));
LONG queryVal = RegQueryValueExW(hKey, L"Path", 0, NULL, (LPBYTE)buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
buffer[bufferSize / sizeof(WCHAR)] = 0;
//...
}
Alternatively, use RegGetValue() instead, which handles the null terminator for you:
WCHAR buffer[512+1];
DWORD bufferSize = sizeof(buffer);
LONG queryVal = RegGetValueW(hKey, NULL, L"Path", RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ, NULL, buffer, &bufferSize);
if (queryVal == ERROR_SUCCESS)
{
//...
}

c++ RegSetValueEx sets only one char value in registry

I'm casting (char * ) on data and i'm getting only one char value in the registry. if
i don't use the casting msvc 2010 tells me that the argument type LPCTSTR is incompatible with const char *.
can someone help me?
HKEY hKey;
LPCTSTR sk = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
LONG openRes = RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_ALL_ACCESS , &hKey);
if (openRes==ERROR_SUCCESS) {
printf("Success opening key.");
} else {
printf("Error opening key.");
}
LPCTSTR value = TEXT("SomeKey");
LPCTSTR data = L"TestData\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.");
}
cout << setRes << endl;
LONG closeOut = RegCloseKey(hKey);
if (closeOut == ERROR_SUCCESS) {
printf("Success closing key.");
} else {
printf("Error closing key.");
}
strlen(data) is probably returning a value of 1, as strlen expects a char* and L"TestData\0" is wide. Use TEXT("TestData\0") and call _tcslen(data).
Note that RegSetValueEx expects the sizeof the data, so use _tcslen(data) * sizeof(TCHAR)
Where are you casting data?
Either way, it looks like you may be working with wide characters, but you seem to be using "plain old" strlen - instead of wcslen or some other function intended to work with wide-character strings.
replace the L"TestData" by _T("TestData"); and strlen(data)+1 by tcslen(data) * sizeof(TCHAR));
so your code looks like this :
LPCTSTR value = TEXT("SomeKey");
LPCTSTR data = TEXT("TestData");
LONG setRes = RegSetValueEx(hKey, value, 0, REG_SZ, (LPBYTE)data, _tcslen(data) * sizeof(TCHAR));