Registry RegQueryValueExW - c++

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;

Related

LPSTREAM unable to read into CString

I'm attempting to read text into a CString using an LPSTREAM, but it doesn't seem to be working correctly, here is the code that I'm calling:
static HRESULT UTL_ReadStreamTxt(MyStorage* pSrcStg, const char* pszStream, CString* myCStr, int size)
{
HRESULT hrRet = STG_E_INVALIDPARAMETER;
LPSTREAM lpSrc = NULL;
ULONG ul;
TRY
{
USES_CONVERSION;
HRESULT hrSrc = pSrcStg->GetStg()->OpenStream(CT2COLE(strSrc),
NULL,
STGM_READ | STGM_SHARE_EXCLUSIVE,
0,
&lpSrc);
if (hrSrc != NOERROR)
{
hrRet = hrSrc;
}
else
{
hrRet = lpSrc->Read(&myCStr, size, NULL); // Read into CString
}
}
CATCH_ALL(e)
{
hrRet = STG_E_UNKNOWN;
}
END_CATCH_ALL
_AfxRelease((LPUNKNOWN*)&lpSrc);
return hrRet;
}
When it reads into the string, Visual Studio says that the data in the CString is corrupted.
The compound storage's stream contents are the following:
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
I'm not entirely sure I'm using Read() correctly, How do I fix this issue?
The main problem is that you are passing a bad pointer to Read(). You are passing the memory address of the myCStr parameter itself, not the address of the CString being pointed at, or more accurately, the memory address of a character buffer that the CString owns. The code compiles only because Read() takes a simple void* pointer to a buffer, and any pointer is implicitly convertible to void*.
Also note that CString is based on TCHAR, which maps to either char or wchar_t depending on whether you are compiling your project for ANSI/MBCS or Unicode. So, reading from the stream directly into a CString will only work correctly if:
the stream contains ANSI characters and TCHAR maps to char.
the stream contains UTF-16 characters and TCHAR maps to wchar_t.
If the stream's character type does not match the character type used by CString, you would have to first read the stream into an intermediate buffer and then convert that to TCHAR before it can be stored in the CString.
Try something more like this:
static HRESULT UTL_ReadStreamTxt(MyStorage* pSrcStg, const char* pszStream, CString* myCStr, int size)
{
HRESULT hrRet = STG_E_INVALIDPARAMETER;
LPSTREAM lpSrc = NULL;
ULONG ul;
LPVOID buffer;
TRY
{
USES_CONVERSION;
HRESULT hrSrc = pSrcStg->GetStg()->OpenStream(CT2COLE(strSrc),
NULL,
STGM_READ | STGM_SHARE_EXCLUSIVE,
0,
&lpSrc);
if (hrSrc != S_OK)
{
hrRet = hrSrc;
}
else
{
// if the stream's character type matches TCHAR...
buffer = myCStr->GetBuffer(size / sizeof(TCHAR));
hrRet = lpSrc->Read(buffer, size, &ul);
myCStr->ReleaseBuffer(ul / sizeof(TCHAR));
// else, if the stream's character type is 'char' and TCHAR is 'wchar_t'...
CStringA tmp;
buffer = tmp.GetBuffer(size);
hrRet = lpSrc->Read(buffer, size, &ul);
tmp.ReleaseBuffer(ul);
*myCStr = CString((LPSTR)tmp, tmp.GetLength());
// else, if the stream's character type is 'wchar_t' and TCHAR is 'char'...
CStringW tmp;
buffer = tmp.GetBuffer(size / sizeof(wchar_t));
hrRet = lpSrc->Read(buffer, size, &ul);
tmp.ReleaseBuffer(ul / sizeof(wchar_t));
*myCStr = CString((LPWSTR)tmp, tmp.GetLength());
// alternatively, you can do the above 2 cases more generically...
typedef CStringT<char or wchar_t> CStreamString;
CStreamString tmp;
buffer = tmp.GetBuffer(size / sizeof(CStreamString::XCHAR));
hrRet = lpSrc->Read(buffer, size, &ul);
tmp.ReleaseBuffer(ul / sizeof(CStreamString::XCHAR));
*myCStr = CString((CStreamString::PXSTR)tmp, tmp.GetLength());
}
}
CATCH_ALL(e)
{
hrRet = STG_E_UNKNOWN;
}
END_CATCH_ALL
_AfxRelease((LPUNKNOWN*)&lpSrc);
return hrRet;
}

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.

How can I convert PCWSTR to a char[] or wchar_t[]

I'm trying to create a file, where one of the parameters has been passed in to the method and is of the type PCWSTR. My code creates a .url file and saves the Url into the file:
wchar_t array1[] = "[InternetShortcut]\nURL=";
wchar_t array2[] = pdwFavoriteUrl;
wchar_t * DataBuffer = new wchar_t[wcslen(array1) + std::strlen(array2) + 1];
std::strcpy(DataBuffer,array1);
std::strcat(DataBuffer,array2);
// Write data to file
DWORD dwBytesToWrite = (DWORD)strlen(DataBuffer);
DWORD dwBytesWritten = 0;
BOOL bErrorFlag = FALSE;
bErrorFlag = WriteFile(hFile, DataBuffer, dwBytesToWrite, &dwBytesWritten, NULL);
if (FALSE == bErrorFlag)
{
// Log error
hr = E_FAIL;
}
else
{
if (dwBytesWritten != dwBytesToWrite)
{
// Log error
hr = E_FAIL;
}
else
{
// Log success
hr = S_OK;
//_tprintf(TEXT("Wrote %d bytes to %s successfully.\n"), dwBytesWritten, argv[1]);
}
}
CloseHandle(hFile);
I am aware that the code will not compile as-is, since there are conflicting versions of unicode and non-unicode string methods. The line of interest is this one:
wchar_t array2[] = pdwFavoriteUrl;
pdwFavoriteUrl is of type PCWSTR and there is no way around it. Please help convert it to wchar_t[] (preferred) or char[].
AFAIK PCWSTR is just an alias for wchar_t* and in case it is null-terminated that the simplest thing to do would be using it to construct an object of type std::wstring. Just pass it to constructor:
PCWSTR wcstr = L"My String";
std::wstring wstr(wcstr);
and work with std::wstring objects instead of doing evil stuff such as:
wchar_t * DataBuffer = new wchar_t[wcslen(array1) + std::strlen(array2) + 1];
which will probably bring you nothing but unpleasant problems and memory leaks.
Remove
wchar_t array2[] = pdwFavoriteUrl;
and change the call to strcat to
std::strcat(DataBuffer, pwdFavoriteUrl);
(and similarly, replace array2 with pwdFavoriteUrl in the call to strlen.)
Note that PCWSTR is just
typedef const wchar_t * PCWSTR;

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.

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