How to convert LPWSTR* (or WCHAR*) to LPWSTR - c++

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

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;

C++ Win32 Getting a registry key

const char* Launcher::GetProjectName()
{
PVOID data;
LPDWORD pcbData;
HKEY OpenResult;
LSTATUS status = RegOpenKeyEx(HKEY_CURRENT_USER, L"Environment", NULL, KEY_READ, &OpenResult);
if (status != ERROR_SUCCESS)
{
LOG(ERROR) << "Could not found registry key 'Environment'";
}
else
{
LPCWSTR project_name_key = L"project_name";
DWORD data_type;
WCHAR value[255];
PVOID pvData = value;
DWORD size = sizeof(value);
status = RegGetValue(OpenResult, NULL, project_name_key, RRF_RT_ANY, &data_type, pvData, &size);
if (status != ERROR_SUCCESS)
{
LOG(ERROR) << "Could not found registry value 'project_name'";
}
else
{
switch (data_type)
{
case REG_DWORD:
wprintf(L"Value data: %x\n", *(DWORD*)pvData);
break;
case REG_SZ:
wprintf(L"Value data: %s\n", (PWSTR)pvData);
}
}
RegCloseKey(OpenResult);
}
return 0;
}
I'm trying to get this registry key I made named "project_name" and return it as a char* or a std::string. However, I'm getting garbage data in pvData. What am I doing wrong here? I've seen some other stackoverflow posts and tried to replicate their setup as well but nothing is working. My entire goal here is to retrieve an environment variable using the windows registry.
I think there's a mismatch of ANSI and Unicode expectations. Your code is likely compiling for ANSI, but you're passing a wide-char buffer. Let's just explicitly call the A version of the Registry functions so you can stay in the ANSI string space.
Instead of this:
WCHAR value[255];
PVOID pvData = value;
DWORD size = sizeof(value);
status = RegGetValue(OpenResult, NULL, project_name_key, RRF_RT_ANY, &data_type, pvData, &size);
Use this:
char value[255];
DWORD size = sizeof(value);
status = RegGetValueA(OpenResult, NULL, project_name_key, RRF_RT_ANY, &data_type, value, &size);
Then, return a std::string as follows:
Declare your function to return a string, not a pointer:
const std::string Launcher::GetProjectName()
Then simply return value as a string;
return std::string(value);

Registry RegQueryValueExW

Is it possible to read a value in the Registry not to an array of chars but directly to an AnsiString in this case?
LONG result;
wchar_t buf[255] = {0};
DWORD dwBufSize = sizeof(buf);
String d = "Nazwa";
DWORD dwType = REG_SZ;
result = ::RegQueryValueExW( hkSoftware, (LPCWSTR)(d.c_str()), NULL, &dwType, (LPBYTE)&buf, &dwBufSize );
First off, your code example is not using AnsiString. In C++Builder 2009 and later, String is an alias for UnicodeString instead.
And yes, you can use UnicodeString with RegQueryValueExW(), without using a typecast. UnicodeString::c_str() returns a WideChar*, and WideChar is an alias for wchar_t on Windows, so WideChar* (aka wchar_t *) is implicitly convertible to LPCWSTR (aka const wchar_t *), eg:
LONG result;
wchar_t buf[255] = {0};
DWORD dwBufSize = sizeof(buf);
UnicodeString d = L"Nazwa";
DWORD dwType = REG_SZ;
result = ::RegQueryValueExW( hkSoftware, d.c_str(), NULL, &dwType, reinterpret_cast<LPBYTE>(&buf), &dwBufSize );
You can also use UnicodeString as a buffer to receive string data from RegQueryValueExW(), eg:
LONG result;
UnicodeString buf;
buf.SetLength(...);
DWORD dwBufSize = ByteLength(buf);
UnicodeString d = L"Nazwa";
DWORD dwType = REG_SZ;
result = ::RegQueryValueExW( hkSoftware, d.c_str(), NULL, &dwType, reinterpret_cast<LPBYTE>(buf.c_str()), &dwBufSize );
if ( result == 0 ) {
buf.SetLength(dwBufSize/sizeof(WideChar));
...
}
That being said, you should consider using C++Builder's TRegistry class instead of using the Win32 Registry API directly. TRegistry has many methods for reading different kinds of data, including ReadString() for String data, eg:
#include <Registry.hpp>
TRegistry *Reg = new TRegistry;
String buf;
Reg->RootKey = ...;
if (Reg->OpenKeyReadOnly(_D("...")))
{
buf = Reg->ReadString(_D("Nazwa"));
Reg->CloseKey();
}
delete Reg;

C++ read Registry

i try to read the Registry in my NPAPI-Plugin:
bool ScriptablePluginObject::Invoke(NPObject* obj, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result) {
ScriptablePluginObject *thisObj = (ScriptablePluginObject*) obj;
char* name = npnfuncs->utf8fromidentifier(methodName);
LPCWSTR game_path = getRegKey(L"SOFTWARE\\World of RPG", L"Path");
MessageBox(NULL, game_path, L"Debugging", MB_TOPMOST);
/* ... */
}
LPCWSTR ScriptablePluginObject::getRegKey(LPCWSTR location, LPCWSTR name) {
HKEY hKey;
LPBYTE folder = new BYTE[MAX_PATH];
DWORD dwSize = sizeof(folder);
long registry = RegOpenKeyEx(HKEY_LOCAL_MACHINE, location, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
long entry = RegQueryValueEx(hKey, name, NULL, REG_NONE, folder, &dwSize);
if(registry != ERROR_SUCCESS) {
return L"Error1";
}
if(entry != ERROR_SUCCESS) {
return L"Error2";
}
RegCloseKey(hKey);
folder[dwSize / sizeof(folder[0])] = '\0';
return (LPCWSTR) folder;
}
But it's returned every call Error2. I've tried a lot of changes:
change the Path (with Start and/or Ending \\)
change parameters
I Want to get the Path of HKEY_LOCAL_MACHINE\SOFTWARE\World of RPG\Path:
Anyone can help me? What i'm doing wrong?
Here's the sample I mentioned in the comments above:
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
LSTATUS ReadRegistry ( LPCWSTR sPath, LPCWSTR sKey, LPWSTR pBuffer, DWORD *pBufferSize );
int _tmain(int argc, _TCHAR* argv[])
{
const int BUFFER_SIZE = 1024;
WCHAR sBuffer[BUFFER_SIZE]; // 2048 bytes
DWORD nBufferSize = BUFFER_SIZE * sizeof ( WCHAR );
ZeroMemory ( sBuffer, nBufferSize );
LSTATUS nResult = ReadRegistry ( L"SOFTWARE\\7-Zip", L"Path64",
sBuffer, &nBufferSize );
// check nResult for ERROR_SUCCESS to know if the call succeeded or not
return 0;
}
LSTATUS ReadRegistry ( LPCWSTR sPath, LPCWSTR sKey, LPWSTR pBuffer, LPDWORD pBufferSize )
{
HKEY hKey;
LSTATUS nResult = ::RegOpenKeyEx ( HKEY_LOCAL_MACHINE, sPath,
0, KEY_READ | KEY_WOW64_64KEY, &hKey );
if ( nResult == ERROR_SUCCESS )
{
nResult = ::RegQueryValueEx ( hKey, sKey, NULL, NULL,
(LPBYTE) pBuffer, pBufferSize );
RegCloseKey ( hKey );
}
return ( nResult );
}
Notice how the ReadRegistry function doesn't allocate memory - it takes a buffer and fills it with data. It's a lot easier to deal with memory if you always have the caller allocate memory. If the callee allocates memory, the caller may not know how memory was allocated and it may not know how to free it. (Of course, you can always assume the use of new and delete but things are simpler if only one side does this consistently. If the caller allocates memory, it'll know how to free it. The callee only needs to put data in the allocated space.
Also, notice how the return value of the API functions is checked before proceeding to the next call - this is important because this tells you if you got a useful registry handle back or not and whether you need to close it or not.
(This sample is really just C, not C++ but it still applies.)
In getRegKey(), your folder variable is a pointer, so sizeof(folder) is 4 (if compiling for 32bit) or 8 (if compiling for 64bit). Thus RegQueryValueEx() fails with an ERROR_MORE_DATA error code.
You are also using the wrong data type for the array. You need to use WCHAR instead of BYTE.
Change this:
LPBYTE folder = new BYTE[MAX_PATH];
DWORD dwSize = sizeof(folder);
To this:
LPWSTR folder = new WCHAR[MAX_PATH];
DWORD dwSize = sizeof(WCHAR) * MAX_PATH;
With that said, you are leaking the memory pointed to by folder, since you never delete[] it.

RegOpenKeyEx returns ERROR_NOACCESS

I am trying to read a registy key under windows 7 x64 using the following code:
static void ReadRegistryKey(HKEY hkey, TCHAR* path)
{
HKEY hkey2;
TCHAR value[MAX_PATH];
TCHAR data[4096];
const DWORD dataLength = 4096 * sizeof(TCHAR);
const DWORD valueLength = MAX_PATH+1;
DWORD returnval;
DWORD type = 0;
HLOCAL mem = LocalAlloc(LPTR, 260);
char * pc = (char*)mem;
pc++;
wchar_t* pwc = (wchar_t*)pc;
lstrcpy(pwc, path);
// Does key exist?
returnval = RegOpenKeyEx(hkey, pwc, 0 , KEY_READ | KEY_WOW64_64KEY, &hkey2);
if(returnval == ERROR_SUCCESS)
{
int i = 0;
while(returnval == ERROR_SUCCESS)
{
DWORD actualLength = dataLength;
DWORD actualValueLength = valueLength;
returnval = RegEnumValueW( hkey2,
i,
value,
&actualValueLength,
NULL,
&type,
(LPBYTE)data,
&actualLength
);
if(returnval == ERROR_NO_MORE_ITEMS)
{
_tprintf(_T("NO MORE KEYS FOUND in %s\n"), path);
break;
}
if(returnval == ERROR_SUCCESS)
{
// STUFF
}
}
}
}
When I use KEY_READ | KEY_WOW64_32KEY I get the values stored under the 32Bit registry but when I use the code above trying to read the "normal" 64bit registy I get the error code 0x3e6 (ERROR_NOACCESS)
The way i call the method:
ReadRegistryKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run");
What can I do to read the 64bit registry values?
Thanks
I think the allocation and pointer arithmetic of pwc is causing the problem. Pass in the path directly into the RegOpenKeyEx function.
It's also worth noting that the lstrcpy will cause a buffer overflow if path is longer than 260 bytes. Instead use StringCchCopy in Windows to give a string copy that will only copy up to the number of bytes available in the destination buffer.