c++ RegCreateKeyEx LPCWSTR from std::string - c++

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.

Related

Can't cast void pointer returned by RegGetValueA

I'm trying to access the registry using the RegGetValueA function, but I can't cast the void pointer passed to the function. I just get the (value?) of the pointer itself.
Here's my code:
LSTATUS res;
LPCSTR lpSubKey = "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{071c9b48-7c32-4621-a0ac-3f809523288f}";
LPCSTR lpValue = "InstallSource";
PVOID pvData = new PVOID;
LPDWORD pcbData = new DWORD;
res = RegGetValueA(
HKEY_LOCAL_MACHINE,
lpSubKey,
lpValue,
RRF_RT_ANY,
NULL,
pvData,
pcbData);
string* data = static_cast<string*>(pvData);
cout << data << "\n";
cout << pvData;
output:
000000000045A240
000000000045A240
Any help would be much appreciated.
link to documentation:
https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-reggetvaluea
You are using the function incorrectly.
First off, you shouldn't be accessing Wow6432Node directly at all. The function has flags for accessing 32bit and 64bit keys when dealing with WOW64.
More importantly, you are giving the function a void* pointer that doesn't point at valid memory for your purpose. When reading a string value from the Registry, you must pre-allocate a character buffer of sufficient size, then pass the address of that buffer to the function. You can ask the function for the necessary buffer size.
The code should look more like the following instead:
LSTATUS res;
LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{071c9b48-7c32-4621-a0ac-3f809523288f}";
LPCSTR lpValue = "InstallSource";
char *pszData = NULL;
DWORD cbData = 0;
res = RegGetValueA( HKEY_LOCAL_MACHINE, lpSubKey, lpValue, RRF_RT_REG_SZ | RRF_SUBKEY_WOW6432KEY, NULL, NULL, &cbData);
if (res != ERROR_SUCCESS) ...
pszData = new char[cbData];
res = RegGetValueA( HKEY_LOCAL_MACHINE, lpSubKey, lpValue, RRF_RT_REG_SZ | RRF_SUBKEY_WOW6432KEY, NULL, pszData, &cbData);
if (res != ERROR_SUCCESS) ...
cout << pszData << "\n";
delete[] pszData;

Creating a file with the same name as registry

I want to create a text file with the same name as a registry.
Say, I get the variable valueName, and I want it's value to be the name of a .txt file in C:\ How can I do that?
Almost final code:
void EnumerateValues(HKEY hKey, DWORD numValues)
{
for (DWORD dwIndex = 0; dwIndex < numValues; dwIndex++)
{BOOL bErrorFlag = FALSE;
char valueName[64];
DWORD valNameLen = sizeof(valueName);
DWORD dataType;
DWORD dataSize = 0;
DWORD retval = RegEnumValue(hKey, dwIndex, valueName, &valNameLen,
NULL, &dataType, NULL, &dataSize);
if (retval == ERROR_SUCCESS)
{//pregatesc calea
char* val = new char[strlen(valueName)];
sprintf(val, "C:\\%s.txt", valueName);
printf("S-a creat fisierul: %s\n", val);
//creez/suprascriu fisierul
HANDLE hFile;
hFile=CreateFile(val,GENERIC_WRITE | GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{ printf("Eroare la creat fisierul %s!\n",val);
}
//sciru in fisier
char str[] = "Example text testing WriteFile";
DWORD bytesWritten=0;
DWORD dwBytesToWrite = (DWORD)strlen(str);
bErrorFlag=WriteFile(hFile, str, dwBytesToWrite, &bytesWritten, NULL);
if (FALSE == bErrorFlag)
{
printf("Eroare la scriere in fisier\n");
}
//inchid fisierul
CloseHandle(hFile);
}
//eroare regenumv
else printf("\nError RegEnumValue");
}
}
The fundamental problem is that you seem to want to convert a registry key, HKEY into a path. And there's no API to do that. You will need to keep track of the path and pass it to the function in the question, along with the HKEY.
You are passing uninitialized values to RegEnumValue, specifically dataSize. Since you don't care about the data, don't ask for it. Pass NULL for the data pointer, and zero for data size.
Your call to new is not allocating enough memory. You need space for the directory name, the file extension, and the null-terminator.
These problems are exacerbated by your complete neglect for error checking. That might sound harsh, but frankly you need some shock treatment. In order to be able to fail gracefully you need to check for errors. More pressing for you, in order to be able to debug code, you need to check for errors.
You've tagged the code C++ but write as if it were C. If you really are using C++ then you can use standard containers, std::string, avoid raw memory allocation and the result leaks. Yes, you code leaks as it stands.
first of all your program is more C like than C++, but if you want to solve this in C++ you can use stringstream in the following way:
std::stringstream stream;
stream << "C:\\";
stream << valueName;
stream << ".txt";
std::string filename(stream.str());
HANDLE hFile=CreateFile(filename.c_str() ,GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_NEW , FILE_ATTRIBUTE_NORMAL,NULL);
Also you need a include:
#include <sstream>

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)
{
//...
}

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

RegSetValueEx does not set in unicode project build

I'm trying to write data to registry, but it always writes foreigner language instead because the setvalue is "MyApp"
CStringA temp(setvalue);//setvalue is CString type
const BYTE* pData = (const BYTE*)(LPCSTR)temp;
lResult = RegSetValueEx(hKey, path, NULL, REG_SZ, (LPBYTE)pData, sizeof(pData));
RegCloseKey(hKey);
if(lResult == ERROR_SUCCESS || lResult == ERROR_MORE_DATA)
return true;
else
return false;
thanks.
The way you are converting CString to BYTE* is causing the problem. No need of using CStringA.
Try this conversion of CString to TCHAR. This should work
LPTSTR lpszData = new TCHAR[setvalue.GetLength()+1]; // setvalue is CString type...
_tcscpy(lpszData , csTemp);
lResult = RegSetValueEx(hKey, path, NULL, REG_SZ, (LPBYTE)lpszData, setvalue.GetLength()+1);
delete[] lpszData;// don't forget to do this.
Try RegSetValueExA(). You are calling a function which is expecting unicode strings. the A() function takes ANSI args
Any Win32 API function that accepts TCHAR, LPTSTR or LPCTSTR parameters will accept either Ansi or Unicode data depending on whether the UNICODE conditional is defined during compiling (RTL functions like _tcscpy use the _UNICODE conditional instead). So what's really happening in this case is that when you call RegSetValueEx() in your code, it gets resolved by the compiler to either calling RegSetValueExA() (Ansi) or RegSetValueExW() (Unicode) depending on the UNICODE conditional.
The CStringA class is for Ansi data only. You have to convert its data to Unicode when calling RegSetValueExW().
To do what you are attempting, you need to either:
1) call RegSetValueExA() explicitally instead of RegSetValueEx() generically if you contiinue using the CStringA class:
CStringA temp(setvalue);
lResult = RegSetValueExA(hKey, path, NULL, REG_SZ, (LPBYTE)(LPSTR)temp, (temp.GetLength() + 1) * sizeof(CHAR));
2) Use the CString class instead of the CStringA class. CString is based on TCHAR, so it is also influenced by the UNICODE conditional, and thus matches the format that RegSetValuEx() is expecting:
CString temp(setvalue);
lResult = RegSetValueEx(hKey, path, NULL, REG_SZ, (LPBYTE)(LPTSTR)temp, (temp.GetLength() + 1) * sizeof(TCHAR));
In the latter case, if your setvalue variable is already a CString, then just use it as-is, no need to create a temp copy of it:
lResult = RegSetValueEx(hKey, path, NULL, REG_SZ, (LPBYTE)(LPTSTR)setvalue, (setvalue.GetLength() + 1) * sizeof(TCHAR));